代码之家  ›  专栏  ›  技术社区  ›  johnny

什么决定了linq语句中的where能够解析什么?

  •  0
  • johnny  · 技术社区  · 6 年前

    在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 });
    

    我想知道为什么它在那里工作,而不是在加入后的地方。如果我在连接的末尾执行where,编译器仍然知道myrecords字段,包括active。

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

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

    1 回复  |  直到 6 年前
        1
  •  3
  •   Rafal    6 年前

    在第一个示例中应用的筛选器类型不正确。blue linq语法为您提供了很多魔力,使这个查询更易于阅读。实际发生的事情是创建一些匿名类型,其中包含对项目的引用。注意,在where子句中可以使用 p cse 变量也是。当你把这个因素考虑到你的表达中,你可能会认为它是这样的 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 你可以应用你的过滤器。