How to make a compound “or” clause in Linq?

前端 未结 5 1676
南笙
南笙 2021-01-05 23:00

If you\'re adding \"and\" conditions to a Linq query, it\'s easy to do it like so:

var q = MyTable;
if (condition1)
  q = q.Where(t => t.Field1 == value1)         


        
相关标签:
5条回答
  • 2021-01-05 23:24

    Use the following:

    var q = MyTable;
    q = q.Where(
         t => (condition1 && t.Field1 == value1) || (condition2 && t.Field2 > t.Field3));
    
    0 讨论(0)
  • 2021-01-05 23:38
    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)));
    
    0 讨论(0)
  • 2021-01-05 23:47

    This is the same answer I gave here

    As Marc Gravell said it involves expression-tree combining.

    This article shows you how to do that. It takes a bit of work to initially set it up. But its worth it.

    Alternate solution is to use Predicate Builder. The article does not explain very well what is actually happening under-the-hood. But the above article explains it nicely

    0 讨论(0)
  • 2021-01-05 23:48

    You can use a PredicateBuilder and use it to build an Or based expression:

     var predicate = PredicateBuilder.False<Product>();
    
     predicate = predicate.Or (t => t.Field1 == value1);
     predicate = predicate.Or (t => t.Field2 > t.Field3);
    
     q = q.Where (predicate);
    

    You can read more about it here: http://www.albahari.com/nutshell/predicatebuilder.aspx

    Replace the Product in PredicateBuilder.False<Product>() with your queried object.

    Note that you start from a False predicate as you want to use Or. If You'd want an And predicate, Yuo should start from a True

    0 讨论(0)
  • 2021-01-05 23:48

    There is one way to do this that involves using expression trees. This way you build the Boolean expression yourself. It's pretty straight forward the tricky part though is that you need to rebase the parameters because otherwise it is going to refer the original lambda expression. See below for an example:

    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));
        }
    }
    

    In the above example I'm being very harsh, I'm effectively replacing any parameter with this single new parameter that is being used to create the new expression. However, given the signature of this extension method it shouldn't really be possible to call this method with parameters such that it would cause an error. It is however going to be a problem if you involve more than one parameter.

    0 讨论(0)
提交回复
热议问题