为什么这个LINQ join语句不起作用?

Mic*_*kel 10 c# linq linq-to-entities entity-framework join

我有这个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();
Run Code Online (Sandbox Code Playgroud)

哪个生成此错误:

无法创建类型为'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;
    }
}
Run Code Online (Sandbox Code Playgroud)

你能看出我做错了什么吗?代码编译完美,_ctx.Items和itemScores都包含正确的值.

Jon*_*eet 21

是的,它编译得很好 - 问题是它无法将其转换为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);
Run Code Online (Sandbox Code Playgroud)

现在,它正在进行内存中查询的连接,这在某种程度上是不必要的.您可以改为使用字典:

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]));
Run Code Online (Sandbox Code Playgroud)

  • @Mickel:`AsEnumerable`没有立即执行查询 - 但它返回一个`IEnumerable <T>`而不是`IQueryable <T>`,因此查询的其余部分将使用`Enumerable.xxx`而不是`Queryable.xxx`.当最终需要执行该查询时,它将执行数据库中的第一部分,以及内存中的第二部分. (2认同)