简体   繁体   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();

i get message of possible NullReferenceException which is correct. 我得到可能的NullReferenceException消息是正确的。

So I make 所以我做了

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();

which works but statement is calling two times and can be slow so i try to make 哪个有效,但声明是两次调用,可能很慢,所以我试图制作

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();

but i get 但我明白了

lambda expression with a statement body can not be converted to an expression tree. 具有语句体的lambda表达式无法转换为表达式树。

What can i do? 我能做什么? Ss first example correct even if i call two times p.Categories.OrderBy(q => q.Name).FirstOrDefault(). 即使我打了两次p.Categories.OrderBy(q => q.Name).FirstOrDefault().第一个例子也是正确的p.Categories.OrderBy(q => q.Name).FirstOrDefault().

I am thinking that this can be slow. 我在想这可能很慢。 I have 200k rows in database. 我在数据库中有200k行。

i get message of possible NullReferenceException which is correct. 我得到可能的NullReferenceException消息是正确的。

It isn't clear which system is producing this message. 目前尚不清楚哪个系统正在生成此消息。 Resharper? ReSharper的?

Anyway, in this case, if this really is LINQ to Entities, the warning is spurious. 无论如何,在这种情况下,如果这确实是LINQ to Entities,则警告是虚假的。 LINQ to Entities performs automatic 'deep null coalescing' in many cases, and this is one such case. LINQ to Entities在许多情况下执行自动“深度空合并”,这就是这种情况。

In your original query: 在您的原始查询中:

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

...there will be no NullReferenceException if an article has no category associated with it. ...如果文章没有与之关联的类别,则不会出现NullReferenceException Instead, the ordering value will be taken as null for such articles (meaning articles with no categories at all will turn up first), which it appears is precisely what you want. 相反,对于这些文章,排序值将被视为null (意味着根本没有类别的文章将首先出现),它看起来正是您想要的。 So no extra effort is required from your side! 因此,您不需要额外的努力!

Do note that with other LINQ providers (such as LINQ to Objects), the behaviour can be quite different, and .FirstOrDefault().XXX is indeed a risky expression. 请注意,对于其他LINQ提供程序(例如LINQ to Objects),行为可能完全不同,而.FirstOrDefault().XXX确实是一个冒险的表达式。

On another note, don't prematurely optimize. 另一方面,不要过早地优化。 If you already have a working solution, benchmark it. 如果您已经有一个可行的解决方案,请对其进 If it's too slow, investigate why - in this case, the clues are in the generated SQL. 如果它太慢,请调查原因 - 在这种情况下,线索在生成的SQL中。 The LINQ to Entities query optimizer can often be smarter than you think. LINQ to Entities查询优化器通常比您想象的更智能。 :) :)

Your second example will indeed produce much more complex SQL query but it is up to database if this query will really be slower. 您的第二个示例确实会产生更复杂的SQL查询,但如果此查询确实会更慢,则由数据库决定。 Anyway you can simply change your first query little bit and it should work as expected without that warning: 无论如何,你可以简单地改变你的第一个查询,它应该按预期工作,没有这个警告:

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

The issue in your query is selecting Name after you call FirstOrDefault so if you project the result prior to call FirstOrDefault it should not produce the warning but there will be additional subselect in resulting SQL. 查询中的问题是在调用FirstOrDefault之后选择Name ,因此如果在调用FirstOrDefault之前投影结果,则不应生成警告,但在结果SQL中将有其他子选择。

Btw. 顺便说一句。 @Ani's answer is correct. @Ani的答案是对的。

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

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

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