繁体   English   中英

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

[英]Entity Framework and lambda expression tree (deep null coalescing)

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().第一个例子也是正确的p.Categories.OrderBy(q => q.Name).FirstOrDefault().

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

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

目前尚不清楚哪个系统正在生成此消息。 ReSharper的?

无论如何,在这种情况下,如果这确实是LINQ to Entities,则警告是虚假的。 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表达式无法转换为表达式树”看起来您不能使用花括号表示的代码块。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM