【问题标题】:How to extract a where clause expression tree from IQueryable如何从 IQueryable 中提取 where 子句表达式树
【发布时间】:2019-01-11 13:18:44
【问题描述】:

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

使用 ExpressionBuilder,我可以组成一个左右表达式>,但要做到这一点,我需要从我的 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/

谢谢!

【问题讨论】:

  • list.Expression 给你什么?
  • 一个表达式对象,但不是一个表达式>
  • 试试这个:((UnaryExpression)((MethodCallExpression)q.Expression).Arguments[1]).Operand.
  • 不知道我能用这个做什么。它给了我一个 UnaryExpression 是的,但是,我怎样才能从中得到一个 Expression> ?
  • 实际上,Arguments[1].OperandExpression&lt;Func&lt;T,bool&gt;&gt; - 您必须转换为 UnaryExpression 才能获得 Arguments 字段。 LINQPad 和它的 Dump 方法对此很有帮助,C# Reference Source 也是如此。

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


【解决方案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 和表达式树的内部结构,并且可能会在将来的某个时候中断。

【讨论】:

  • 我离得太近了!我唯一需要注意的是当我们升级框架时,但从那时起,我们可能已经重构了需要此代码的部分,以便更健壮和高效(使用全文搜索)谢谢!!
  • @Stéphan 没问题 - 修复了我留下的 Accounts 应该是 T :)
  • 你在 if 块的最后一行也有错字! (wf 而不是我们) ;)
  • @Stéphan 谢谢,已修复。
猜你喜欢
  • 2020-01-11
  • 1970-01-01
  • 2022-08-16
  • 2015-04-21
  • 1970-01-01
  • 2011-03-27
  • 1970-01-01
  • 1970-01-01
  • 2015-08-20
相关资源
最近更新 更多