我有几个LINQ到实体查询,这些查询命中了相同的两个表并具有相同的几个条件。我要做的是在多个查询之间共享where子句。例如,说我有这个:
from t0 in db.Table0
from t1 in db.Table1
from t2 in db.Table2
where t0.Field7 == 'something'
&& t1.Field1 > t2.Field3
&& t2.NavigationProperty(t => t.Field4 == t1.Field2).Any()
select t0
我想要的是能够说出这样的话:
Func<Table1, Table2, bool> specialCondition
= (t1, t2) => t1.Field1 > t2.Field3
&& t2.NavigationProperty(t => t.Field4 == t1.Field2).Any();
from t0 in db.Table0
from t1 in db.Table1
from t2 in db.Table2
where t0.Field7 == 'something' && specialCondition(t1, t2)
select t1
这会生成有意义的The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.
。它无法将任意.NET函数/委托代码解析为可以传递给数据库的东西。
我在互联网上看到的一切都说表达树可以正常工作。我的问题是我可以声明它(它与函数的语法几乎相同),我不知道如何使用它。
Expression<Func<Table1, Table2, bool>> specialCondition
= (t1, t2) => t1.Field1 > t2.Field3
&& t2.NavigationProperty(t => t.Field4 == t1.Field2).Any();
我该怎么办?如何将其传递给LINQ2EF?
更新:按照@Mic的建议使用LinqKit工作解决方案,从NuGet中提取(注意.AsExpandable()
和.Invoke
以及剪切导入的LinqKit引用和命名空间):
Expression<Func<Table1, Table2, bool>> specialCondition
= (t1, t2) => t1.Field1 > t2.Field3
&& t2.NavigationProperty(t => t.Field4 == t1.Field2).Any();
from t0 in db.Table0.AsExpandable()
from t1 in db.Table1
from t2 in db.Table2
where t0.Field7 == 'something' && specialCondition.Invoke(t1, t2)
select t1
检查LinqPad,第一个完全内联版本和最终的LinqKit Expression版本生成相同的SQL和结果。非常感谢大家的建议和帮助。
答案 0 :(得分:3)
此类构造在本机L2S / L2Entities提供程序中是不可能的。您必须使用支持表达式扩展的LINQKit库。
答案 1 :(得分:1)
使用CompiledQuery
创建委托。我很确定它在LINQ to Entities中有效。您只需要将DataContext
类型作为第一个参数。
Func<MyDataContext, Table1, Table2, bool> specialCondition =
CompiledQuery.Create(
(MyDataContext dc, Table1 t1, Table2 t2) =>
t1.Field1 > t2.Field3
&& t2.NavigationProperty(t => t.Field4 == t1.Field2).Any());
然后使用它,您应该能够这样做:
var query =
from t0 in db.Table0
from t1 in db.Table1
from t2 in db.Table2
where t0.Field7 == 'something' && specialCondition(db, t1, t2)
select t1
答案 2 :(得分:0)
将LINQ查询重写为LINQ表达式语法,并将表达式传递给Where(expression)
。