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

时间:2011-12-04 11:10:28

标签: c# entity-framework

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

,Ss第一个例子也是正确的

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

3 个答案:

答案 0 :(得分:4)

  

我收到可能的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查询优化器通常比您想象的更智能。 :)

答案 1 :(得分:2)

你的第二个例子确实会产生更复杂的SQL查询,但是如果这个查询真的会慢一些,那就是数据库了。无论如何,你可以简单地改变你的第一个查询,它应该按预期工作,没有那个警告:

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

您的查询中的问题是在您致电Name后选择FirstOrDefault,因此如果您在致电FirstOrDefault之前预测结果,则不会产生警告,但会有其他子选择结果SQL。

顺便说一下。 @ Ani的回答是正确的。

答案 2 :(得分:0)

这似乎是一个重复的答案:"A lambda expression with a statement body cannot be converted to an expression tree"您似乎无法使用花括号表示的代码块。