I have one queryable where I have used various Where
and WhereBetween
statements to narrow the collection down to a certain set. Now I need to add kind of a Where || WhereBetween
. In other words, I can't just chain them together like I have up till now, cause that will work as an And. So, how can I do this?
I see two possibilities:
- Create two queryables from the one I have, one using the
Where
, and one usingWhereBetween
. And then concatenate them. Don't know if this is even possible? Also, although not in my particular case, you would most likely end up with duplicates... - Somehow merge the
Where
expression and the expression created in theWhereBetween
with some sort of Or.
The first, as mentioned, I am not sure is even possible. And if it was, I'm not so sure it is a good way to do it.
The second, I can see as an option, but not totally sure about all the details. Below is the WhereBetween
method from my other question, which I now use and it works great:
public static IQueryable<TSource> WhereBetween<TSource, TValue>(
this IQueryable<TSource> source,
Expression<Func<TSource, TValue>> selector,
IEnumerable<Range<TValue>> ranges)
{
var param = Expression.Parameter(typeof(TSource), "x");
var member = Expression.Invoke(selector, param);
Expression body = null;
foreach (var range in ranges)
{
var filter = Expression.AndAlso(
Expression.GreaterThanOrEqual(member,
Expression.Constant(range.A, typeof(TValue))),
Expression.LessThanOrEqual(member,
Expression.Constant(range.B, typeof(TValue))));
body = body == null ? filter : Expression.OrElse(body, filter);
}
return body == null ? source : source.Where(
Expression.Lambda<Func<TSource, bool>>(body, param));
}
I'm thinking that I could maybe extract the expression building portion of it into a new method. Perhaps like this:
public static IQueryable<TSource> WhereBetween<TSource, TValue>(
this IQueryable<TSource> source,
Expression<Func<TSource, TValue>> selector,
IEnumerable<Range<TValue>> ranges)
{
return source.Where(WhereBetween(selector, ranges));
}
public static Expression<Func<TSource, bool>> WhereBetween<TSource, TValue>(
Expression<Func<TSource, TValue>> selector,
IEnumerable<Range<TValue>> ranges)
{
var param = Expression.Parameter(typeof(TSource), "x");
var member = Expression.Invoke(selector, param);
Expression body = null;
foreach (var range in ranges)
{
var filter = Expression.AndAlso(
Expression.GreaterThanOrEqual(member,
Expression.Constant(range.A, typeof(TValue))),
Expression.LessThanOrEqual(member,
Expression.Constant(range.B, typeof(TValue))));
body = body == null ? filter : Expression.OrElse(body, filter);
}
return body == null
? ø => true
: Expression.Lambda<Func<TSource, bool>>(body, param);
}
I could then use that new method to get the expression instead of the queryable. So, lets say I have the WhereBetween(ø => ø.Id, someRange)
and for example ø => ø.SomeValue == null
. How can I combine those two with Or? I'm looking at the Expression.OrElse
used in the WhereBetween
method, and I think that might be what I need, or maybe this the Expression.Or
. But I'm very unstable on this expression stuff, so I am not sure what to choose here, or even if I am on the right track :p
Could someone give me some pointers here?