У меня есть этот LINQ-запрос:
// types...
LinkedList<WeightedItem> itemScores = new LinkedList<WeightedItem>();
var result = from i in _ctx.Items
join s in itemScores on i.Id equals s._id
orderby s._score descending
select new ItemSearchResult(i, s._score);
// this fails:
return result.ToList();
Который генерирует эту ошибку:
Не удалось создать постоянную стоимость типа 'Система. Наборы. Универсальный. IEnumerable '1'.
Только типы примитивов ('такие как Int32, Строка и Гуид') поддерживаются в этом контексте.
[РЕДАКТИРОВАНИЕ] Здесь является кодом WeightedItem
:
public class WeightedItem
{
public int _id;
public decimal? _score;
public WeightedItem(int id, decimal? score)
{
_id = id;
_score = score;
}
}
Можно ли видеть то, что я сделал неправильно? Код компилирует отлично и оба _ctx. Объекты и itemScores содержат собственные значения.
Да, он отлично скомпилирует - проблема в том, что он не может перевести его на SQL. При обращении к "локальным" значениям, фреймворк сущностей должен придумать, что с ними делать, когда нужно создать SQL-запрос. В принципе, он не может справиться с соединением коллекции in-memory с таблицей БД.
Одна вещь, которая может работать, это использование Contains
вместо этого. Не знаю, сработает ли LinkedList
, но я думаю, что List
сработает, по крайней мере, в LINQ к SQL:
List<int> requiredScoreIds = itemScores.Select(x => x._id).ToList();
var tmp = (from i in _ctx.Items
where requiredScoreIds.Contains(i.Id)
orderby s._score descending
select i).AsEnumerable();
// Now do the join in memory to get the score
var result = from i in tmp
join s in itemScores on i.Id equals s._id
select new ItemSearchResult(i, s._score);
Теперь, когда мы делаем соединение в запросе in-memory, это несколько ненужно. Вместо этого можно использовать словарь:
List<int> requiredScoreIds = itemScores.Select(x => x._id).ToList();
var tmp = (from i in _ctx.Items
where requiredScoreIds.Contains(i.Id)
orderby s._score descending
select i).AsEnumerable();
// Create a map from score ID to actual score
Dictionary<int, decimal?> map = itemScores.ToDictionary(x => x._id,
x => x._score);
var result = tmp.Select(i => new ItemSearchResult(i, map[i.Id]));
Вы не можете соединить список в памяти с запрашиваемым объектом. Вам нужно сделать что-то вроде этого:
var criteria = itemScores.Select(x => x._id).ToList();
var result_tag = (from i in _ctx.Items
where criteria.Contains(i.ID)
select i).ToList();
var result = from i in result_tag
join s in itemScores on i.ID equals s._id
orderby s._score descending
select new ItemSearchResult(i, s._score);