在没有 PredicateBuilder 的情况下将谓词动态添加到表达式

Posted

技术标签:

【中文标题】在没有 PredicateBuilder 的情况下将谓词动态添加到表达式【英文标题】:Add dynamically predicate to expression without PredicateBuilder 【发布时间】:2019-04-14 09:26:32 【问题描述】:

我使用linqToEntities 并想动态添加OR 条件。

我知道there is a great library PredicateBuilder by brother Albahari 可以解决我的任务,但我不能使用它。

我的情况如下:

IEnumerable<Condition> conditions = new List<Condition>()

    new Condition()IdReference = 1, TableName = "Table1" ,
    new Condition()IdReference = 2, TableName = "Table2" ,
    new Condition()IdReference = 3, TableName = "Table3" , 
    // and so on
;

我拥有的是:

var histories = db.History as IQueryable<History>;
foreach (var cond in conditions)

     //What code should be here to be translated into:
     /*
     histories = histories
        .Where(h => h.IdReference == 1 && h.TableName =="Table1" 
            || h.IdReference == 2 && h.TableName == "Table2"
            || h.IdReference == 3 && h.TableName == "Table3");
            // and so on
     */
    

但是,我事先不知道conditions 会有多少。 如何从IEnumerable&lt;Condition&gt; 动态添加OR 条件?

【问题讨论】:

如果您没有太多组合,只需使用一些条件:if(thisIsTheCase) histories = histories.Where(// put your conditions else if(another Case) histories = histories.Where(// put your conditions add more if else,直到您涵盖所有情况。您也可以通过创建动态表达式来做到这一点,但这并不容易,因为您需要组合表达式。 为什么不能使用PredicateBuilder @CodingYoshi 因为我的代码不会通过代码审查。 【参考方案1】:

不确定使用谓词构建器有什么问题 - 它不一定是 LINQ Kit 包,所谓的谓词构建器通常是具有 2 个扩展方法的单个静态类 - 例如 Universal Predicate Builder 或我自己的 PredicateUtils来自Establish a link between two lists in linq to entities where clause 和类似的。

无论如何,一旦你想要它,当然可以只使用普通的Expression 类静态方法来构建它。

添加以下内容以消除在每次调用之前编写Expression. 的需要:

using static System.Linq.Expressions.Expression;

然后使用这样的东西:

if (conditions.Any())

    var parameter = Parameter(typeof(History));
    var body = conditions
        .Select(condition => Expression.Constant(condition))
        .Select(condition => Expression.AndAlso(
        Expression.Equal(
            Expression.PropertyOrField(parameter, nameof(History.IdReference)),
            Expression.Convert(
                  Expression.PropertyOrField(condition, nameof(Condition.IdReference))
                , Expression.PropertyOrField(parameter, nameof(History.IdReference)).Type)
        ),
        Expression.Equal(
            Expression.PropertyOrField(parameter, nameof(History.TableName)),
            Expression.Convert(
                  Expression.PropertyOrField(condition, nameof(Condition.TableName))
                , Expression.PropertyOrField(parameter, nameof(History.TableName)).Type)
         )
        ))
        .Aggregate(Expression.OrElse);                      
    var predicate = Lambda<Func<History, bool>>(body, parameter);
    histories = histories.Where(predicate);

【讨论】:

【参考方案2】:

我理解你的意思

var histories = db.History as IQueryable<History>;
foreach (var cond in conditions)

     //What code should be here to be translated into:

     histories = histories
        .Where(h => h.IdReference == cond.IdReference && 
      h.TableName ==cond.TableName );

    

【讨论】:

他直到运行时才知道条件。如果他们知道,这将起作用。 据我了解,他不知道历史列表中有多少条件,但他在条件列表中有固定条件,因此在条件列表中循环并比较!正如我所想:) 链接Wheres 是and 而不是or

以上是关于在没有 PredicateBuilder 的情况下将谓词动态添加到表达式的主要内容,如果未能解决你的问题,请参考以下文章

用PredicateBuilder实现Linq动态拼接查询

将 LinqKit PredicateBuilder 用于相关模型(EF Core)

Entity Framework 4.1 Code First - 使用 LinqKit PredicateBuilder 时忽略包含

如何使用 PredicateBuilder、EF Core 5 和 Postgresql 10+ 执行不区分大小写和重音的 LIKE(子字符串)查询?

在没有库的情况下制作矩阵/在列表中没有任何内容的情况下插入嵌套列表

如何在没有引用的情况下复制对象?