Почему не работает этот оператор соединения LINQ?

c# entity-framework join linq linq-to-entities

Вопрос

У меня есть этот 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();

Который генерирует эту ошибку:

Невозможно создать постоянное значение типа 'System.Collections.Generic.IEnumerable`1'.
В этом контексте поддерживаются только примитивные типы (такие как Int32, String и Guid).

[РЕДАКТИРОВАТЬ] Вот код WeightedItem :

public class WeightedItem
{
    public int _id;
    public decimal? _score;

    public WeightedItem(int id, decimal? score)
    {
        _id = id;
        _score = score;
    }
}

Вы видите, что я сделал не так? Код отлично компилируется, и _ctx.Items и itemScores содержат правильные значения.

Принятый ответ

Да, он скомпилируется нормально - проблема в том, что он не может перевести его на SQL. Когда вы ссылаетесь на «локальные» значения, структура сущностей должна решить, что с ними делать, когда ей нужно создать запрос SQL. По сути, он не справляется с объединением коллекции в памяти и таблицы базы данных.

Единственное, что может сработать, это использовать вместо Contains . Я не знаю, будет ли LinkedList<T> работать для этого, но я считаю, что List<T> работает, по крайней мере, в LINQ to 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);

Теперь мы выполняем объединение в запросе в памяти, что не является необходимым. Вместо этого вы можете использовать словарь:

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);


Related

Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Является ли этот КБ законным? Да, узнайте, почему
Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Является ли этот КБ законным? Да, узнайте, почему