【发布时间】:2018-11-15 19:44:34
【问题描述】:
我有这个,
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,然后使用过滤器。如果我在最后做 where,
(mc, p) => new { MyCourse= mc, Person = p }).Where(mc=>mc.MyCourse.Active == 1)
我得到了一个很好的连接查询。否则引擎首先将所有行查询到内存中。包含数千行的两个独立查询。
我在 SO 和其他地方看到了大量关于此的问题。当有多个表时,我找不到一个告诉我如何使用动态Where Expression<Func<T,TResult>> 从联接中执行表达式。
目标是基于表达式(不是Dynamic Linq,也没有第三方)进行动态查询语句。事实上,这个问题声称最后的 Where 速度较慢,但在我的程序中它执行了正确的查询与联接。
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 看起来不错,Explain 计划显示最少的行检索。
【问题讨论】:
-
你在使用实体框架吗?你的
MyCourse表中的PeopleId是外键吗? -
是的。它只是名称上的外键,而不是这样定义的数据库中的外键。
-
我明白了。如果是这样的话会更容易,因为 Entity Framework 会从您的 Person 类为您创建一个参考列表。但无论如何,还是可以做到的。
-
首先,查询的开始应该是
db.MyCourse.Where(filter)。但我认为根据您的 EF 版本,您应该寻找各种全局查询过滤器选项。 -
@GertArnold 问题是当我以这种方式使用它时,Linq 会带回所有 Person 记录,36k 然后调整活动课程的行。如果我将过滤器放在它的末尾并输入 x=>x.MyCourse.Active == 1 的表达式,那么我会得到一个带有 Join 的查询(从我在 SQL Profiler 上看到的)。
标签: c# entity-framework linq lambda expression-trees