【问题标题】:Dynamic LINQ OR Conditions动态 LINQ OR 条件
【发布时间】:2010-12-08 18:45:58
【问题描述】:

我希望使用 LINQ 对类似于

的集合执行多个 where 条件
IEnumerable<Object> items;
items.Where(p => p.FirstName = "John");
items.Where(p => p.LastName = "Smith");

除了有多个 AND 条件(如本例所示)之外,我希望有多个 OR 条件。

编辑 抱歉,澄清一下,我不知道我会有多少这样的条件

items.Where(p => p.FirstName = "John" || p => p.LastName = "Smith")

不会工作。

基本上,这就是我想要做的:

foreach(var name in names)
{
    items = items.Where(p => p.Name == name);
}

【问题讨论】:

    标签: linq


    【解决方案1】:

    使用PredicateBuilder:

    假设您要编写实现关键字样式搜索的 LINQ to SQL 或实体框架查询。换句话说,一个查询返回其描述包含部分或全部给定关键字集的行......

    理想的方法是动态构造一个执行基于的谓词的lambda表达式树。

    在促使您手动构建表达式树的所有事情中,对动态谓词的需求在典型的业务应用程序中最为常见。幸运的是,可以编写一组简单且可重用的扩展方法,从根本上简化此任务。这就是我们 PredicateBuilder 类的作用...

    【讨论】:

    • 干得好,但不适用于 LINQ to Entities 和实体框架 (6):LINQ to Entities 不支持 LINQ 表达式节点类型“Invoke”。
    【解决方案2】:

    听起来您的姓名白名单仅在运行时才知道。也许试试这个:

    string[] names = new string[] {"John", "foo", "bar"};
    
    var matching = items.Where(x => names.Contains(x.Name));
    

    【讨论】:

    • 这对我来说非常有用,因为我已经在研究 Linq 动态库只是为了做到这一点。谢谢!
    【解决方案3】:

    您可以使用.Union() 返回满足任何条件的结果。

    var results = items.Where(p => p.FirstName == "John")
         .Union(items.Where(p => p.LastName == "Smith"));
    

    这不如使用|| 运算符。从您的编辑中不清楚为什么这不起作用。

    【讨论】:

      【解决方案4】:
          public static Expression<Func<T, bool>> OrTheseFiltersTogether<T>(
            this IEnumerable<Expression<Func<T, bool>>> filters)
          {
              Expression<Func<T, bool>> firstFilter = filters.FirstOrDefault();
              if (firstFilter == null)
              {
                  Expression<Func<T, bool>> alwaysTrue = x => true;
                  return alwaysTrue;
              }
      
              var body = firstFilter.Body;
              var param = firstFilter.Parameters.ToArray();
              foreach (var nextFilter in filters.Skip(1))
              {
                  var nextBody = Expression.Invoke(nextFilter, param);
                  body = Expression.OrElse(body, nextBody);
              }
              Expression<Func<T, bool>> result = Expression.Lambda<Func<T, bool>>(body, param);
              return result;
          }
      

      然后,稍后:

      List<Expression<Func<Person, bool>>> filters = names
        .Select<string, Expression<Func<Person, bool>>>(name => 
          p => p.Name == name
        ).ToList();
      
      Expression<Func<Person, bool>> filterOfOrs = filters.OrTheseFiltersTogether();
      
      query = query.Where<Person>(filterOfOrs);
      

      【讨论】:

      • LINQ to Entities 不支持调用 :(
      • @user288281 如果这是真的 - 可悲。表达式树操作应该是 .net 级别的东西。拥有被树引用的 LinqToSql 或 LinqToEntities 实例不应该影响您从中创建新树的能力,而不是拥有整数或字符串。
      • 有谁知道如何转换这个样本,以便它与实体框架一起工作。如何避免调用表达式?由于有tomasp.net/blog/linq-expand.aspx 框架,它一定是可能的。
      【解决方案5】:

      您不能使 Where 子句动态化,但您可以动态创建传递给它的 Lambda 表达式。创建正确的Expression,对其进行编译并将生成的 lambda 表达式作为参数传递给 Where 子句。

      编辑:

      好的,您似乎可以跳过必须手动创建表达式的部分,并可以使用PredicateBuilder ,正如AS-CII 已经回答的那样。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-05-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-12
        • 2012-11-03
        • 1970-01-01
        相关资源
        最近更新 更多