Extend IQueryable<T> Where() as OR instead of AND relationship
Solution 1:
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 Expression
s 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<Expression<Func<int, bool>>>();
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<T> WhereAny<T>(
this IQueryable<T> source,
params Expression<Func<T,bool>>[] 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<Func<T, bool>>(body, param);
return source.Where(lambda);
}
Solution 2:
Use PredicateBuilder<T>
. It's probably what you want.