Extend IQueryable Where() as OR instead of AND relationship

后端 未结 4 1880
有刺的猬
有刺的猬 2020-12-16 23:15

I am using my own extension methods of IQueryable<> to create chainable queries such as FindAll().FindInZip(12345).NameStartsWith(\"XYZ\").OrderByHowIWantIt() etc. which

4条回答
  •  借酒劲吻你
    2020-12-16 23:53

    I'm assuming the different parts of the query are only known at runtime, i.e. you can't just use || in a where...

    One lazy option is Concat - but this tends to lead to poor TSQL etc; however, I tend to be inclined to write custom Expressions instead. The approach to take depends on what the provider is, as LINQ-to-SQL supports different options to EF (for example) - which has a genuine impact here (since you can't use sub-expressions with EF). Can you tell us which?


    Here's some code that should work with LINQ-to-SQL; if you build an array (or list, and call .ToArray()) of expressions, it should work fine; example is LINQ-to-Objects, but should still work:

        static void Main()
        {
            var data = (new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).AsQueryable();
    
            var predicates = new List>>();
            predicates.Add(i => i % 3 == 0);
            predicates.Add(i => i >= 8);           
    
            foreach (var item in data.WhereAny(predicates.ToArray()))
            {
                Console.WriteLine(item);
            }
        }
    
        public static IQueryable WhereAny(
            this IQueryable source,
            params Expression>[] predicates)
        {
            if (source == null) throw new ArgumentNullException("source");
            if (predicates == null) throw new ArgumentNullException("predicates");
            if (predicates.Length == 0) return source.Where(x => false); // no matches!
            if (predicates.Length == 1) return source.Where(predicates[0]); // simple
    
            var param = Expression.Parameter(typeof(T), "x");
            Expression body = Expression.Invoke(predicates[0], param);
            for (int i = 1; i < predicates.Length; i++)
            {
                body = Expression.OrElse(body, Expression.Invoke(predicates[i], param));
            }
            var lambda = Expression.Lambda>(body, param);
            return source.Where(lambda);
        }
    

提交回复
热议问题