[英]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.