简体   繁体   English

如何在Join之后的两个表的Where子句中为Linq创建Lambda表达式?

[英]How can I create an Lambda Expression for Linq in the Where clause for two tables after the Join?

I have this, 我有这个,

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

and then this, 然后这个

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

The reason I need to do it this way is because if I put the filter on the MyCourse table first with, 之所以需要这样做,是因为如果我首先将过滤器放在MyCourse表上,

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

The SQL created brings back all of the People and all of the MyCourse and then uses the filter. 创建的SQL将带回所有人员和所有MyCourse,然后使用过滤器。 If I do the where at the end, 如果我在最后做

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

I get a good query with the Joins. 我对Joins有很好的查询。 Else the engine queries all the rows into memory first. 否则,引擎首先将所有行查询到内存中。 Two separate queries with thousands of rows. 具有数千行的两个独立查询。

I have seen a tremendous amount of questions on SO and elsewhere about this. 我已经在SO和其他地方看到了很多与此相关的问题。 I cannot find one that tells me how to do the Expression when there is more than one table, from a Join, using a dynamic Where Expression<Func<T,TResult>> . 我找不到一个告诉我如何使用动态Where Expression<Func<T,TResult>>从Join中创建多个表的Where Expression<Func<T,TResult>>

The goal is to make a dynamic query statement based upon Expressions (not Dynamic Linq , and no third party.) In fact, this question claims the Where at the end is slower, but in my program it does the correct query with Joins. 目的是根据表达式(而不是Dynamic Linq ,并且没有第三方)来创建动态查询语句。实际上,该问题声称“ Where”结尾处较慢,但在我的程序中它使用Joins进行了正确的查询。

MyCourse has a PersonId and People has a PersonId. MyCourse具有一个PersonId,而People具有一个PersonId。 If I wrote this by hand it'd look like, 如果我亲手写的话,

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

(Those are just example columns for the question. They're not really what I want from the above query, except Active == 1.) (这些只是问题的示例列。它们不是我在上述查询中真正想要的,除了Active ==1。)

Where clause with Join in lambda expression 使用Lambda表达式中的Join子句

Update: FWIW, I was able to get it working this this, 更新: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
    );

I did not do navigation properties or anything else. 我没有导航属性或其他任何内容。 And I was able to use it like this, 我可以这样使用它

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

The produced SQL looked good, and the Explain plan showed minimal row retrieval. 产生的SQL看起来不错,并且Explain计划显示了最少的行检索。

I suspect calling Compile() on your Expression is causing your trouble. 我怀疑在您的Expression上调用Compile()会造成麻烦。 Your full query includes the Join , but you've already compiled the Where clause, so it can't compile the entire query including the Join together. 您的完整查询包括Join ,但是您已经编译了Where子句,因此它无法编译包括Join Together的整个查询。 That might be why it's grabbing the entire table because it's executing the Where by itself first, then doing the Join later. 这可能就是为什么它要抓住整个表的原因,因为它首先自己执行Where ,然后再执行Join

But you don't need to call Compile() . 但是您不需要调用Compile() Just pass the Expression into Where() : 只需将Expression传递到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();

Somewhat unrelated to your actual problem, but if you created the foreign keys, you can simplify this a bit. 某种程度上与您的实际问题无关,但是如果您创建了外键,则可以稍微简化一下。 Update your model in your Visual Studio project if you haven't already. 如果尚未更新模型,请在Visual Studio项目中进行更新。 Your Person class will change to have a list of MyCourse and your MyCourse class will have a list of Person . 您的Person类将更改为具有MyCourse的列表,而您的MyCourse类将具有Person的列表。

So you can do something like: 因此,您可以执行以下操作:

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 handles the join, and each MyCourse returned will have a Person property. Linq处理MyCourse ,并且返回的每个MyCourse都将具有Person属性。

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

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