将LINQ中的多个where子句连接为OR而不是AND

时间:2020-12-10 12:03:10

Is there anyway to join LINQ where clauses as OR ?

无论如何加入LINQ的条款是OR吗?

var ints = new [] { 1, 3, 5, 7 };

var query = from i in ints select i;

query = query.Where (q => q == 3);

query = query..Where (q => q == 7);

What I want is the ability to dynamically add where clauses but make them use OR instead of AND

我想要的是能够动态添加where子句但是使用OR而不是AND

7 个解决方案

#1


12  

If you want to stay with your strong-typing Linq queries you should look into LinqKit and predicate building. I have used this for something similar and found it to work well with And / Or stacking of filters.

如果你想继续使用强类型的Linq查询,你应该查看LinqKit和谓词构建。我已经将它用于类似的东西,并发现它与And / Or堆叠过滤器配合得很好。

Check out the C#4.0/3.0 in a Nutshell excerpt for more in depth info. Here is a snip from my code:

在Nutshell摘录中查看C#4.0 / 3.0以获取更多深入信息。这是我的代码中的一个片段:

        //Setup the initial predicate obj then stack on others:
        basePredicate = basePredicate.And(p => false);
        var predicate1 = PredicateBuilder.True<Person>();

        foreach (SearchParms parm in parms)
        {
            switch (parm.field)
            {
                case "firstname":
                    predicate1 = predicate1.And(p => p.FirstName.Trim().ToLower().Contains(sValue));
                    break;
                //etc...
            }

        }
        //Run a switch based on your and/or parm value to determine stacking:
        if (Parm.isAnd) {
             basePredicate = basePredicate.And(predicate1);
        } else {
             basePredicate = basePredicate.Or(predicate1);
        }

#2


2  

How about something like this?

这样的事怎么样?

var query = from i in ints where CheckConditions(i) select i;

public bool CheckConditions(int i)
{
    var conditions = WhereConditions; //an IEnumerable<Func<int, bool>> of  dynamically added conditions
    foreach (var condition in conditions)
    {
        if (condition(i)) return true;
    }
    return false;
}

You can probably expand this to be a bit cleverer but that's sort of how I'd do it.

你可以扩展这个有点聪明,但这就是我的方式。

EDIT: Sorry the first example was an AND, have changed it now to be an OR. So the first time it encounters a passing condition it returns true.

编辑:对不起,第一个例子是AND,现在已将其更改为OR。所以第一次遇到传递条件时它返回true。

#3


2  

Using ExpressionVisitor to help to build the expression base on two expressions with OR/AND relationship. This answer is from Jeffery Zhao's blog.

使用ExpressionVisitor帮助构建基于具有OR / AND关系的两个表达式的表达式。这个答案来自Jeffery Zhao的博客。

internal class ParameterReplacer : ExpressionVisitor
{
    public ParameterReplacer(ParameterExpression paramExpr)
    {
        this.ParameterExpression = paramExpr;
    }

    public ParameterExpression ParameterExpression { get; private set; }

    public Expression Replace(Expression expr)
    {
        return this.Visit(expr);
    }

    protected override Expression VisitParameter(ParameterExpression p)
    {
        return this.ParameterExpression;
    }
}

public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> one, Expression<Func<T, bool>> another)
{
    var candidateExpr = Expression.Parameter(typeof(T), "candidate");
    var parameterReplacer = new ParameterReplacer(candidateExpr);

    var left = parameterReplacer.Replace(one.Body);
    var right = parameterReplacer.Replace(another.Body);
    var body = Expression.And(left, right);

    return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
}

public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> one, Expression<Func<T, bool>> another)
{
    var candidateExpr = Expression.Parameter(typeof(T), "candidate");
    var parameterReplacer = new ParameterReplacer(candidateExpr);

    var left = parameterReplacer.Replace(one.Body);
    var right = parameterReplacer.Replace(another.Body);
    var body = Expression.Or(left, right);

    return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
}

#4


0  

You can using Union method:

您可以使用Union方法:

var ints = new [] { 1, 3, 5, 7 };
var query = ints.Where(q => q == 3);
query = query.Union(ints.Where(q => q == 7));

#5


-2  

Are you talking about specifying more than one condition in the lambda?

你在谈论在lambda中指定多个条件吗?

query = query.Where(q => q == 3 ||
                         q == 7);

#6


-3  

try this

尝试这个

var ints = new [] { 1, 3, 5, 7 };

var ints = new [] {1,3,5,7};

var query = ints.select(X=>X).where(X=>X==3||X==7);

var query = ints.select(X => X).where(X => X == 3 || X == 7);

#7


-3  

I am trying to do something similar. Here's what I came up with:

我正在尝试做类似的事情。这就是我想出的:

//various test cases
bool useTestCase1 = true;
bool useTestCase2 = true;
bool useTestCase3 = false;

query = query.Where(q => 
                      (q == 3 && useTestCase1 ) ||
                      (q == 7 && useTestCase2 ) ||
                      (q == 10 && useTestCase3 )
                    ); 

#1


12  

If you want to stay with your strong-typing Linq queries you should look into LinqKit and predicate building. I have used this for something similar and found it to work well with And / Or stacking of filters.

如果你想继续使用强类型的Linq查询,你应该查看LinqKit和谓词构建。我已经将它用于类似的东西,并发现它与And / Or堆叠过滤器配合得很好。

Check out the C#4.0/3.0 in a Nutshell excerpt for more in depth info. Here is a snip from my code:

在Nutshell摘录中查看C#4.0 / 3.0以获取更多深入信息。这是我的代码中的一个片段:

        //Setup the initial predicate obj then stack on others:
        basePredicate = basePredicate.And(p => false);
        var predicate1 = PredicateBuilder.True<Person>();

        foreach (SearchParms parm in parms)
        {
            switch (parm.field)
            {
                case "firstname":
                    predicate1 = predicate1.And(p => p.FirstName.Trim().ToLower().Contains(sValue));
                    break;
                //etc...
            }

        }
        //Run a switch based on your and/or parm value to determine stacking:
        if (Parm.isAnd) {
             basePredicate = basePredicate.And(predicate1);
        } else {
             basePredicate = basePredicate.Or(predicate1);
        }

#2


2  

How about something like this?

这样的事怎么样?

var query = from i in ints where CheckConditions(i) select i;

public bool CheckConditions(int i)
{
    var conditions = WhereConditions; //an IEnumerable<Func<int, bool>> of  dynamically added conditions
    foreach (var condition in conditions)
    {
        if (condition(i)) return true;
    }
    return false;
}

You can probably expand this to be a bit cleverer but that's sort of how I'd do it.

你可以扩展这个有点聪明,但这就是我的方式。

EDIT: Sorry the first example was an AND, have changed it now to be an OR. So the first time it encounters a passing condition it returns true.

编辑:对不起,第一个例子是AND,现在已将其更改为OR。所以第一次遇到传递条件时它返回true。

#3


2  

Using ExpressionVisitor to help to build the expression base on two expressions with OR/AND relationship. This answer is from Jeffery Zhao's blog.

使用ExpressionVisitor帮助构建基于具有OR / AND关系的两个表达式的表达式。这个答案来自Jeffery Zhao的博客。

internal class ParameterReplacer : ExpressionVisitor
{
    public ParameterReplacer(ParameterExpression paramExpr)
    {
        this.ParameterExpression = paramExpr;
    }

    public ParameterExpression ParameterExpression { get; private set; }

    public Expression Replace(Expression expr)
    {
        return this.Visit(expr);
    }

    protected override Expression VisitParameter(ParameterExpression p)
    {
        return this.ParameterExpression;
    }
}

public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> one, Expression<Func<T, bool>> another)
{
    var candidateExpr = Expression.Parameter(typeof(T), "candidate");
    var parameterReplacer = new ParameterReplacer(candidateExpr);

    var left = parameterReplacer.Replace(one.Body);
    var right = parameterReplacer.Replace(another.Body);
    var body = Expression.And(left, right);

    return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
}

public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> one, Expression<Func<T, bool>> another)
{
    var candidateExpr = Expression.Parameter(typeof(T), "candidate");
    var parameterReplacer = new ParameterReplacer(candidateExpr);

    var left = parameterReplacer.Replace(one.Body);
    var right = parameterReplacer.Replace(another.Body);
    var body = Expression.Or(left, right);

    return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
}

#4


0  

You can using Union method:

您可以使用Union方法:

var ints = new [] { 1, 3, 5, 7 };
var query = ints.Where(q => q == 3);
query = query.Union(ints.Where(q => q == 7));

#5


-2  

Are you talking about specifying more than one condition in the lambda?

你在谈论在lambda中指定多个条件吗?

query = query.Where(q => q == 3 ||
                         q == 7);

#6


-3  

try this

尝试这个

var ints = new [] { 1, 3, 5, 7 };

var ints = new [] {1,3,5,7};

var query = ints.select(X=>X).where(X=>X==3||X==7);

var query = ints.select(X => X).where(X => X == 3 || X == 7);

#7


-3  

I am trying to do something similar. Here's what I came up with:

我正在尝试做类似的事情。这就是我想出的:

//various test cases
bool useTestCase1 = true;
bool useTestCase2 = true;
bool useTestCase3 = false;

query = query.Where(q => 
                      (q == 3 && useTestCase1 ) ||
                      (q == 7 && useTestCase2 ) ||
                      (q == 10 && useTestCase3 )
                    );