Joining multiple where clauses in LINQ as OR instead of AND

前端 未结 7 908
情书的邮戳
情书的邮戳 2020-12-16 13:33

Is there anyway to join LINQ where clauses as OR ?

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

var query = from i in ints select i;

query = query.Where (q => q ==         


        
相关标签:
7条回答
  • 2020-12-16 14:03

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

    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);
    }
    
    0 讨论(0)
  • 2020-12-16 14:03

    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 )
                        ); 
    
    0 讨论(0)
  • 2020-12-16 14:08

    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.

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

            //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);
            }
    
    0 讨论(0)
  • 2020-12-16 14:19

    You can using Union method:

    var ints = new [] { 1, 3, 5, 7 };
    var query = ints.Where(q => q == 3);
    query = query.Union(ints.Where(q => q == 7));
    
    0 讨论(0)
  • 2020-12-16 14:22

    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.

    0 讨论(0)
  • 2020-12-16 14:25

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

    query = query.Where(q => q == 3 ||
                             q == 7);
    
    0 讨论(0)
提交回复
热议问题