如何从IQueryable提取where子句表达式树

时间:2019-01-11 13:18:45

标签: linq lambda entity-framework-6 expression-trees

我需要根据现有IQueryable对象的某些条件动态地在where子句中添加“ Or”子句。

使用ExpressionBuilder,我可以编写一个左右Expression>,但是为此,我需要从IQueryable实例中提取Expression>。 有可能吗?

示例代码:

var list = _context.Set<T>().Where(x=>x.Id == 1);

if(someValue)
{
    var leftExpression = list.???? //I would extract the Expression<Func<T, bool>> here
    var orExpression = (T x) => x.Status == 1;

    var newWhereClause = ExpressionBuilder.Or(leftExpression, orExpression);
    list = list.Where(newWhereClause);
}

ExpressionBuilder代码是从以下链接获取的: https://blogs.msdn.microsoft.com/meek/2008/05/02/linq-to-entities-combining-predicates/

谢谢!

1 个答案:

答案 0 :(得分:1)

您需要做的是分解原始的IQueryable,提取源和查询表达式,然后构建一个新的查询表达式,然后从源和新的查询表达式中创建一个新的IQueryable。如果没有Where,只需将条件添加到原始查询中即可。

IQueryable<T> q = _context.Set<T>().Where(x => x.Id == 1);

if(someValue) {
    Expression<Func<T,bool>> newWhereClause = (T x) => x.Status == 1;
    Expression source;

    if (q.Expression is MethodCallExpression qe && qe.Method.Name == "Where") {
        var we = (MethodCallExpression)q.Expression; // get the call to Where
        var wea1 = (UnaryExpression)we.Arguments[1]; // get the 2nd arg to Where (Quoted Lambda)
        var leftExpr = (Expression<Func<T, bool>>)wea1.Operand; // Extract the lambda from the QuoteExpression
        newWhereClause = ExpressionBuilder.Or(leftExpr, newWhereClause);
        q = q.Provider.CreateQuery<T>(we.Arguments[0]).Where(newWhereClause);
    }
    else
        q = q.Where(newWhereClause);
}

请注意,这取决于LINQ和表达式树的内部,并且将来可能会中断。