实体框架和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行
我得到可能的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表达式不能转换为表达式树"似乎不能使用花括号表示的代码块。