是什么决定Linq语句中的Where能够解析什么?

时间:2018-11-16 15:25:02

标签: c# linq linq-query-syntax

在Linq语句的Where子句中,

  var myClasses = (from b in db.MyRecords
                   join p in db.People on b.PersonId equals p.PersonId
                   join cse in db.Courses on b.CourseId equals cse.CourseId
                   where (b.Active == 1)
                   select new { b });

表达式b.Active==1可以正常工作。但是如果我这样做,

Expression<Func<MyRecords, bool>> filter = my => my.Active == 1;

[更新:由于汉斯的回答,我将其保留为原文,但实际上,我在这里打错了。表达式实际上是使用基础类型,而不是像查询Linq那样由EF生成的复数。我真的有这个,

Expression<Func<MyRecord, bool>> filter = my => my.Active == 1;

]

尝试一下

  var myClasses = (from b in db.MyRecords
                   join p in db.People on b.PersonId equals p.PersonId
                   join cse in db.Courses on b.CourseId equals cse.CourseId
                   where (filter)
                   select new { b });

编译器抱怨

  

无法将查询表达式转换为预期的委托类型,因为某些   块中的返回类型不能隐式转换为   委托返回类型

我对此有很多疑问,但是我不明白为什么它不起作用。我对基本原理有误解,所以我并不是要任何人来编写代码。我想知道Linq想要什么,因此我对Linq有了更好的了解,而不仅仅是使某些事情起作用。例如,这有效

  var myClasses = (from b in db.MyRecords.Where(filter)
                   join p in db.People on b.PersonId equals p.PersonId
                   join cse in db.Courses on b.CourseId equals cse.CourseId
                   select new { b });

我想知道为什么它在那里起作用,而不是在联接之后的位置起作用。如果我在联接末尾执行“位置”,则编译器仍会知道MyRecords字段,包括Active。

认为是我想要的一个适当描述,因为它似乎很适合我。

http://www.albahari.com/nutshell/linqkit.aspx

1 个答案:

答案 0 :(得分:3)

您的过滤器类型错误,将在第一个示例中应用。蓝色linq语法为您提供了很多魔术,使此查询易于阅读。实际发生的情况是创建一些匿名类型,这些类型包含对您的项目的引用。注意,在where子句中,您也可以使用pcse变量。而且,当您将表达式考虑在内时,您可能会发现它实际上就像这样的Expression<Func<Tuple<MyRecords, People, Courses>>,它不是元组而是某种匿名类型。

当您要求resharper将蓝色语法转换为方法链时,它会生成如下代码:

(db.MyRecords.Join(
     db.People, 
     b => b.PersonId,
     p => p.PersonId,
     (b, p) => new {b, p})
  .Join(
       db.Courses,
       t => t.b.CourseId, 
       cse => cse.CourseId,
       (t, cse) => new {t, cse})
   .Where(t => (t.t.b.Active == 1))
   .Select(t => new {t.t.b}));

实际上,您不能像在蓝色语法中那样使用filter变量:

... join cse in db.Courses on b.CourseId equals cse.CourseId
               where (filter)

您将不得不切换到方法调用:

(from b in db.MyRecords
                join p in db.People on b.PersonId equals p.PersonId
                join cse in db.Courses on b.CourseId equals cse.CourseId
                select b)
            .Where(filter)

现在,仅因为我们将内部查询的大小调整为b,您就可以应用过滤器了。