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

如何在联接后的两个表的WHERE子句中为LINQ创建lambda表达式?

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

    我有这个,

     Expression<Func<MyCourse, bool>> filter = mc => mc.Active == 1;
     Func<MyCourse, bool> funcWhere = filter.Compile();
    

    然后这个,

    var myClasses = db.MyCourse.Join(db.People, mc => mc.PersonId, 
    p => p.PersonId, (mc, p) => new { MyCourse= mc, Person = p }).Where(???)
    

    我需要这样做的原因是,如果我首先在mycourse表上放置过滤器,

    db.MyCourse.Where(funcWhere).Join....
    

    创建的SQL返回所有人员和所有mycourse,然后使用过滤器。如果我在最后的地方,

    (mc, p) => new { MyCourse= mc, Person = p }).Where(mc=>mc.MyCourse.Active == 1)
    

    我对联接有一个很好的查询。否则,引擎会先将所有行查询到内存中。两个具有数千行的独立查询。

    关于这一点,我看到了很多关于SO和其他方面的问题。当一个联接中有多个表时,使用动态 Where Expression<Func<T,TResult>> .

    目的是基于表达式(而不是 Dynamic Linq ,而不是第三方。)事实上,这个问题声称结尾的位置比较慢,但在我的程序中,它使用连接执行正确的查询。

    mycourse有一个personid,而people有一个personid。如果我用手写的话,看起来就像,

    select mc.CourseName, p.LastName 
    from MyCourse mc inner join Person p on mc.PersonId = p.PersonId
    where mc.Active = 1;
    

    (这些只是问题的示例列。除了active==1),它们实际上不是我从上面的查询中想要的。

    Where clause with Join in lambda expression

    更新:fwiw,我能让它工作这个,

        var param = Expression.Parameter(typeof(MyClass), "MyClassDebug");
        var exp = Expression.Lambda<Func<MyClass, bool>>(
            Expression.Equal(
                Expression.Property(param, dbParameter),
                Expression.Constant(dbValue)
            ),
            param
        );
    

    我没有做导航属性或其他任何事情。我能像这样使用它,

    var MyQuery = (from recs in dbcontext.MyClass.Where(exp)
                   ...three joins
    

    生成的SQL看起来不错,并且解释计划显示最少的行检索。

    1 回复  |  直到 6 年前
        1
  •  2
  •   Gabriel Luci    6 年前

    我怀疑打电话 Compile() 对你 Expression 是你的麻烦。您的完整查询包括 Join ,但您已经编译了 Where 子句,因此它无法编译整个查询,包括 加入 一起。这可能就是为什么它要抓取整个表,因为它正在执行 在哪里? 先自己做,然后做 加入 后来。

    但你不需要打电话 编译() . 只是通过 表情 进入之内 Where() :

    Expression<Func<MyCourse, bool>> filter = mc => mc.Active == 1;
    var myClasses = db.MyCourse
        .Where(filter)
        .Join(db.People, mc => mc.PersonId, 
    p => p.PersonId, (mc, p) => new { MyCourse= mc, Person = p }).ToList();
    

    有点与实际问题无关,但是如果您创建了外键,您可以将其简化一点。如果还没有,请在Visual Studio项目中更新模型。您的 Person 类将更改为具有 MyCourse 你的 迈尔 类将有一个列表 .

    所以你可以这样做:

    Expression<Func<MyCourse, bool>> filter = mc => mc.Active == 1;
    var courses = db.MyCourse.Include("Person").Where(filter);
    foreach (var course in courses) {
        var person = course.Person; //This is populated with the Person record
    }
    

    Linq处理连接,每个 迈尔 返回将有一个 财产。