动态 LINQ OR 条件

19

我想使用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);
}
5个回答

15

使用 PredicateBuilder

假设你想要编写一个 LINQ to SQL 或 Entity Framework 查询,执行基于关键字的搜索。换句话说,查询返回其描述包含所给出的一组关键字中的部分或全部的行...

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

在典型的商业应用程序中,需要动态谓词是手动构建表达式树的最常见的事情之一。幸运的是,可以编写一组简单且可重用的扩展方法,从而彻底简化此任务。这就是我们的 PredicateBuilder 类扮演的角色...


干得不错,但无法与LINQ to Entities和Entity Framework(6)一起使用:在LINQ to Entities中不支持LINQ表达式节点类型“Invoke”。 - Jürgen Bayer

13
您可以使用.Union()来返回满足任何条件的结果。
var results = items.Where(p => p.FirstName == "John")
     .Union(items.Where(p => p.LastName == "Smith"));

使用 || 操作符会更好。从您的编辑内容来看,为什么不使用该操作符并不清楚。


11

看起来你的名字白名单只有在运行时才知道。也许尝试这样做:

string[] names = new string[] {"John", "foo", "bar"};

var matching = items.Where(x => names.Contains(x.Name));

这对我非常有用,因为我已经在查看Linq动态库来完成这个任务。谢谢! - xleon

3
    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调用 :( - yonexbat
如果这是真的 - 很遗憾。 表达式树操作应该是 .net 级别的东西。引用树的 LinqToSql 或 LinqToEntities 实例不应影响您从中创建新树的能力,就像使用 ints 或 strings 一样。 - Amy B
有人知道如何将这个示例转换为与实体框架一起使用吗?如何避免调用表达式?这必须是可能的,因为有http://tomasp.net/blog/linq-expand.aspx框架。 - yonexbat

0

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

编辑:

好的,看起来你可以跳过手动创建表达式的部分,可以使用PredicateBuilder,正如AS-CII已经回答的那样。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接