在LINQ语句之间共享where子句

时间:2011-12-14 22:27:05

标签: linq entity-framework .net-4.0 linq-to-entities expression-trees

我有几个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和结果。非常感谢大家的建议和帮助。

3 个答案:

答案 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)