实体框架和lambda表达式树(深空合并)

本文关键字:合并 框架 lambda 表达式 实体 | 更新日期: 2023-09-27 18:16:41

var articles = context.Articles.Where(a => a.Id != articleId)
.OrderBy(p => p.Categories.OrderBy(q => q.Name).FirstOrDefault().Name).ToList();

我得到可能的NullReferenceException的消息,这是正确的。

所以我写

var  articles = context.Articles.Where(a => a.Id != articleId)
                               .OrderBy(p =>
                                   (p.Categories.OrderBy(q => q.Name).FirstOrDefault() != null
                                    ? p.Categories.OrderBy(q => q.Name).FirstOrDefault().Name
                                    : null))
                               .Skip(page * pageSize)
                                  .Take(pageSize)
                                  .ToList();

可以,但是语句调用了两次,速度很慢所以我尝试使用

var articles = context.Articles.Where(a => a.Id != articleId)
             .OrderBy(p =>
             {
                 var firstOrDefault = p.Categories.OrderBy(q => q.Name).FirstOrDefault();
                 return firstOrDefault != null ? firstOrDefault.Name : null;
             }).ToList();

但是我得到

带有语句体的

lambda表达式不能转换为表达式树。

我能做什么?第一个例子是正确的,即使我调用两次p.Categories.OrderBy(q => q.Name).FirstOrDefault().

我在想这可能会很慢。我在数据库中有200k行

实体框架和lambda表达式树(深空合并)

我得到可能的NullReferenceException的消息,这是正确的。

不清楚是哪个系统产生了这个消息。Resharper吗?

无论如何,在这种情况下,如果这真的是LINQ到实体,警告是虚假的。LINQ to Entities在很多情况下执行自动'深空合并',这就是其中一个例子。

在原始查询中:

var articles = context.Articles
                      .Where(a => a.Id != articleId)
                      .OrderBy(p => p.Categories
                                     .OrderBy(q => q.Name)
                                     .FirstOrDefault()
                                     .Name)
                       .ToList();

…如果文章没有与之关联的类别,则不会有NullReferenceException。相反,这类文章的排序值将被视为null(这意味着没有任何类别的文章将首先出现),这似乎正是您想要的。所以你不需要额外的努力!

请注意,使用其他LINQ提供程序(例如LINQ to Objects),行为可能会非常不同,并且.FirstOrDefault().XXX确实是一个有风险的表达式。

另一个注意事项,不要过早优化。如果您已经有了一个可行的解决方案,请对其进行基准测试。如果太慢,调查为什么——在这种情况下,线索就在生成的SQL中。LINQ to Entities查询优化器通常比您想象的要聪明。:)

您的第二个示例确实会产生更复杂的SQL查询,但这取决于数据库,如果这个查询真的会更慢。无论如何,你可以简单地改变你的第一个查询,它应该像预期的那样工作,没有警告:

var articles = context.Articles
                      .Where(a => a.Id != articleId)
                      .OrderBy(p => p.Categories
                                     .OrderBy(q => q.Name)
                                     .Select(q => q.Name)
                                     .FirstOrDefault())
                      .ToList();

查询中的问题是在调用FirstOrDefault之后选择Name,因此,如果您在调用FirstOrDefault之前预测结果,则不应产生警告,但会在结果SQL中产生额外的子选择。

顺便说一句。@Ani的答案是正确的

这似乎是一个重复的答案:"带有语句体的lambda表达式不能转换为表达式树"似乎不能使用花括号表示的代码块。