如何在 Join 后的两个表的 Where 子句中为 Linq 创建 Lambda 表达式?
How can I create an Lambda Expression for Linq in the Where clause for two tables after the Join?
我有这个,
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 table 上,
db.MyCourse.Where(funcWhere).Join....
创建的 SQL 带回所有人员和所有 MyCourse,然后使用过滤器。如果我最后做 where,
(mc, p) => new { MyCourse= mc, Person = p }).Where(mc=>mc.MyCourse.Active == 1)
我通过连接得到了很好的查询。否则引擎首先将所有行查询到内存中。具有数千行的两个单独查询。
我在 SO 和其他地方看到了大量关于此的问题。当有多个 table,来自 Join,使用动态 Where Expression<Func<T,TResult>>
.
时,我找不到告诉我如何执行表达式的方法
目标是基于Expression做一个动态查询语句(不是Dynamic Linq,也没有第三方。)其实这道题是说最后的Where比较慢,但是在我的程序中使用 Joins 进行正确的查询。
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 之外,它们并不是我真正想要的上述查询。)
更新: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 看起来不错,Explain 计划显示最少的行检索。
我怀疑在您的 Expression
上调用 Compile()
会给您带来麻烦。您的完整查询包含 Join
,但您已经编译了 Where
子句,因此它无法将包含 Join
的整个查询编译在一起。这可能就是它获取整个 table 的原因,因为它首先自己执行 Where
,然后再执行 Join
。
但您不需要调用 Compile()
。只需将 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();
与您的实际问题有些无关,但如果您创建了外键,则可以稍微简化一下。如果您还没有更新 Visual Studio 项目中的模型。您的 Person
class 将更改为包含 MyCourse
的列表,而您的 MyCourse
class 将包含 Person
.[=28= 的列表]
所以你可以这样做:
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 处理连接,返回的每个 MyCourse
都会有一个 Person
属性.
我有这个,
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 table 上,
db.MyCourse.Where(funcWhere).Join....
创建的 SQL 带回所有人员和所有 MyCourse,然后使用过滤器。如果我最后做 where,
(mc, p) => new { MyCourse= mc, Person = p }).Where(mc=>mc.MyCourse.Active == 1)
我通过连接得到了很好的查询。否则引擎首先将所有行查询到内存中。具有数千行的两个单独查询。
我在 SO 和其他地方看到了大量关于此的问题。当有多个 table,来自 Join,使用动态 Where Expression<Func<T,TResult>>
.
目标是基于Expression做一个动态查询语句(不是Dynamic Linq,也没有第三方。)其实这道题是说最后的Where比较慢,但是在我的程序中使用 Joins 进行正确的查询。
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 之外,它们并不是我真正想要的上述查询。)
更新: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 看起来不错,Explain 计划显示最少的行检索。
我怀疑在您的 Expression
上调用 Compile()
会给您带来麻烦。您的完整查询包含 Join
,但您已经编译了 Where
子句,因此它无法将包含 Join
的整个查询编译在一起。这可能就是它获取整个 table 的原因,因为它首先自己执行 Where
,然后再执行 Join
。
但您不需要调用 Compile()
。只需将 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();
与您的实际问题有些无关,但如果您创建了外键,则可以稍微简化一下。如果您还没有更新 Visual Studio 项目中的模型。您的 Person
class 将更改为包含 MyCourse
的列表,而您的 MyCourse
class 将包含 Person
.[=28= 的列表]
所以你可以这样做:
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 处理连接,返回的每个 MyCourse
都会有一个 Person
属性.