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

C# 为什么这个LINQ join语句不起作用?,c#,linq,entity-framework,join,linq-to-entities,C#,Linq,Entity Framework,Join,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 desc

我有一个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();

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

是的,它会编译得很好-问题是它无法将其转换为SQL。当您引用本地值时,实体框架必须确定在需要创建SQL查询时如何处理它们。它基本上无法处理内存集合和数据库表之间的连接

可能有效的一件事是使用Contains。我不知道LinkedList是否适用于此,但我相信List适用,至少在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);

以防万一_ctx.Items表示的表不是一个大表,您不关心加载 将所有表存储在内存中,然后在内存中对其进行过滤,您只需交换表中项目的顺序即可 join语句,如以下代码段所示:

LinkedList<WeightedItem> itemScores = new LinkedList<WeightedItem>();

var result = from s in itemScores
             join i in _ctx.Items on s._id equals i.Id
             orderby s._score descending
             select new ItemSearchResult(i, s._score);

return result.ToList();
在原始语句中调用了Queryable扩展方法:

IQueryable<TResult> Queryable.Join<TOuter, TInner, TKey, TResult>(
        this IQueryable<TOuter> outer,
        IEnumerable<TInner> inner,
        Expression<Func<TOuter, TKey>> outerKeySelector,
        Expression<Func<TInner, TKey>> innerKeySelector,
        Expression<Func<TOuter, TInner, TResult>> resultSelector
)
IEnumerable<TResult> Enumerable.Join<TOuter, TInner, TKey, TResult>(
        this IEnumerable<TOuter> outer,
        IEnumerable<TInner> inner,
        Func<TOuter, TKey> outerKeySelector,
        Func<TInner, TKey> innerKeySelector,
        Func<TOuter, TInner, TResult> resultSelector
)
在交换的方法中,调用可枚举扩展方法:

IQueryable<TResult> Queryable.Join<TOuter, TInner, TKey, TResult>(
        this IQueryable<TOuter> outer,
        IEnumerable<TInner> inner,
        Expression<Func<TOuter, TKey>> outerKeySelector,
        Expression<Func<TInner, TKey>> innerKeySelector,
        Expression<Func<TOuter, TInner, TResult>> resultSelector
)
IEnumerable<TResult> Enumerable.Join<TOuter, TInner, TKey, TResult>(
        this IEnumerable<TOuter> outer,
        IEnumerable<TInner> inner,
        Func<TOuter, TKey> outerKeySelector,
        Func<TInner, TKey> innerKeySelector,
        Func<TOuter, TInner, TResult> resultSelector
)
因此,在最后一条语句中,full _ctx.Items表被加载到内存中,然后被联接, 通过Linq到对象,到我不知道的关于LinkedList的itemScores列表,我用list尝试了它

我之所以添加这个答案,主要是因为有人可以按相反的顺序键入连接,并将其保留下来 在没有意识到数据库中将要发生什么的情况下工作

我不建议以这种方式加入,尽管它在任何时候都可以用于后台应用程序 涉及的表由很少的记录组成,并且应用程序不会出现相关的性能恶化。
毕竟,这个解决方案保持了代码的整洁。

你能发布WeightedItem的代码吗。DOK,这意味着?啊,见鬼-Jon Skeet打败了我:Jon Skeet是StackOverflow的Chuck Norris,所以.AsEnumerable执行查询并将结果保存在内存中是有意义的?如果不是,代码的哪一部分会执行?@Mickel:AsEnumerable不会立即执行查询-但它会返回IEnumerable而不是IQueryable,因此查询的其余部分将使用Enumerable.xxx而不是Queryable.xxx完成。当该查询最终需要执行时,它将在数据库中执行第一部分,在内存中执行第二部分。