如何在Linq中创建复合“或”子句?

时间:2011-06-19 09:49:55

标签: c# linq

如果您要为Linq查询添加“和”条件,则很容易这样做:

var q = MyTable;
if (condition1)
  q = q.Where(t => t.Field1 == value1);
if (condition2)
  q = q.Where(t => t.Field2 > t.Field3);
// etc.

当你想添加“或”条件时,有没有聪明的方法做同样的事情?

5 个答案:

答案 0 :(得分:6)

您可以使用PredicateBuilder并使用它来构建基于Or的表达式:

 var predicate = PredicateBuilder.False<Product>();

 predicate = predicate.Or (t => t.Field1 == value1);
 predicate = predicate.Or (t => t.Field2 > t.Field3);

 q = q.Where (predicate);

您可以在此处详细了解: http://www.albahari.com/nutshell/predicatebuilder.aspx

Product中的PredicateBuilder.False<Product>()替换为您查询的对象。

请注意,您要从False谓词开始,因为您要使用Or。如果您需要And谓词,则Yuo应从True

开始

答案 1 :(得分:4)

使用以下内容:

var q = MyTable;
q = q.Where(
     t => (condition1 && t.Field1 == value1) || (condition2 && t.Field2 > t.Field3));

答案 2 :(得分:2)

有一种方法可以使用表达式树。这样您就可以自己构建布尔表达式。这很简单,但是你需要 rebase 参数,因为否则它将引用原始的lambda表达式。请参阅下面的示例:

static void Main(string[] args)
{
    var source = new List<int> { 1, 2, 3 };

    var any = new List<Expression<Func<int, bool>>>();

    any.Add(x => x == 1);
    any.Add(x => x == 3);

    foreach (var item in source.AsQueryable().WhereDisjunction(any))
    {
        Console.WriteLine(item);
    }
}

class RewriteSingleParameterUsage : ExpressionVisitor
{
    public ParameterExpression Parameter { get; set; }

    protected override Expression VisitParameter(ParameterExpression node)
    {
        return Parameter;
    }
}

public static IQueryable<T> WhereDisjunction<T>(this IQueryable<T> source, IList<Expression<Func<T, bool>>> any)
{
    switch (any.Count)
    {
        case 0: return source;
        case 1: return source.Where(any[0]);
        default:
            var p = Expression.Parameter(any[0].Parameters[0].Type, any[0].Parameters[0].Name);
            var rw = new RewriteSingleParameterUsage { Parameter = p };
            var expr = rw.Visit(any[0].Body);
            for (int i = 1; i < any.Count; i++)
            {
                expr = Expression.Or(expr, rw.Visit(any[i].Body));
            }
            return source.Where(Expression.Lambda<Func<T, bool>>(expr, p));
    }
}

在上面的例子中,我非常苛刻,我正在用这个用于创建新表达式的新参数替换任何参数。但是,鉴于此扩展方法的签名,实际上不应该使用参数调用此方法,以致它会导致错误。但是,如果涉及多个参数,则会出现问题。

答案 3 :(得分:2)

var q = MyTable;
var conditions = new List<Func<T, bool>>();

 if (condition1)
     conditions.Add(t => ...);
 if (condition2)
     conditions.Add(t => ...);

 q.Where(x => conditions.Any(y => y(x)));

答案 4 :(得分:1)

这与我给出here

的答案相同

正如Marc Gravell所说,它涉及表达式树组合。

这个article向您展示了如何做到这一点。初始设置它需要一些工作。但它值得。

替代解决方案是使用Predicate Builder。这篇文章没有很好地解释实际发生在幕后的情况。但上面的文章很好地解释了