C# 实体框架和lambda表达式树(深度空合并)
我得到了正确的可能为NullReferenceException的消息 所以我C# 实体框架和lambda表达式树(深度空合并),c#,entity-framework,C#,Entity Framework,我得到了正确的可能为NullReferenceException的消息 所以我 var articles = context.Articles.Where(a => a.Id != articleId) .OrderBy(p => p.Categories.OrderBy(q => q.Name).FirstOrDefault().Name).ToList(); 这是可行的,但声明调用了两次,可能会很慢,所以我尝试 var articles = context.Articl
var articles = context.Articles.Where(a => a.Id != articleId)
.OrderBy(p => p.Categories.OrderBy(q => q.Name).FirstOrDefault().Name).ToList();
这是可行的,但声明调用了两次,可能会很慢,所以我尝试
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();
但我明白了
具有语句体的lambda表达式无法转换为
表达式树
我能做什么?即使我调用了两次p.Categories.OrderBy(q=>q.Name).FirstOrDefault()。
我认为这可能是缓慢的。我在数据库中有200000行。这似乎是一个重复的答案:您似乎无法使用大括号表示的代码块 我得到了正确的可能为NullReferenceException的消息 目前还不清楚是哪个系统产生了这条信息。再竖琴 无论如何,在这种情况下,如果这真的是LINQ到实体,那么警告是虚假的。 LINQ to Entities在许多情况下执行自动“深度空合并”,这就是一种情况。 在原始查询中:
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();
…如果一篇文章没有与之关联的类别,则不会出现NullReferenceException
。相反,对于此类文章,排序值将被视为null
(意味着没有任何类别的文章将首先出现),这似乎正是您想要的。所以不需要你方付出额外的努力
请注意,对于其他LINQ提供程序(例如LINQ to对象),行为可能会有很大不同,而且.FirstOrDefault().XXX
确实是一个危险的表达式
另一方面,不要过早地优化。如果您已经有了一个可行的解决方案,请对其进行基准测试。如果太慢,请调查原因——在本例中,线索在生成的SQL中。LINQ to Entities查询优化器通常比您想象的更智能。:) 您的第二个示例确实会生成更复杂的SQL查询,但该查询是否真的较慢取决于数据库。无论如何,您只需稍微更改第一个查询,它就可以在没有警告的情况下正常工作:
var articles = context.Articles
.Where(a => a.Id != articleId)
.OrderBy(p => p.Categories
.OrderBy(q => q.Name)
.FirstOrDefault()
.Name)
.ToList();
查询中的问题是在调用FirstOrDefault
之后选择Name
,因此如果在调用FirstOrDefault
之前投影结果,则不会产生警告,但在生成的SQL中会有额外的子选择
顺便说一句,@Ani的答案是正确的。您是否有必要使用
lambda
?通过重新分解一些lambda
表达式,可能更容易解决您的解决方案并使代码更具可读性。LINQ to Entities无法将自定义方法调用转换为等效的SQL。很公平-我没有意识到它使用的是实体框架。是的,这是正确的答案。Linq to entities将正确解释第一个查询。是的,resharper给我此消息。所以这个信息是不相关的。那么为什么resharper会给出这个消息呢。@senzacionale:resharper(目前)可能不够聪明,无法考虑LINQ提供程序的特性。在一般情况下,警告是正确的-在这种情况下不可能发生。如果需要,您可以使用注释禁用警告(它为您提供了执行此操作的选项)。
var articles = context.Articles
.Where(a => a.Id != articleId)
.OrderBy(p => p.Categories
.OrderBy(q => q.Name)
.Select(q => q.Name)
.FirstOrDefault())
.ToList();