Today I had to write some code that had nullable parameters that could filter the results of a Linq query. At first I was doing “if” statements on the nullable parameters to determine if they needed to be applied. This was pretty verbose so I came up with a more succinct approach with conditional Linq extension methods.
First define conditional extension methods on IQueryable<>:
public static class IQueryableExtensions
{
public static IQueryable<T> Where<T>(this IQueryable<T> query, bool condition,
System.Linq.Expressions.Expression<Func<T, bool>> predicate)
{
return condition ? query.Where(predicate) : query;
}
public static IQueryable<T> Take<T>(this IQueryable<T> query, bool condition, int count)
{
return condition ? query.Take(count) : query;
}
public static IQueryable<T> Skip<T>(this IQueryable<T> query, bool condition, int count)
{
return condition ? query.Skip(count) : query;
}
// ...
}
Then you get a nice fluent way to conditionally apply the parameters:
public List<Template> EnumerateTemplates(
Guid accountId,
int? startIndex,
int? maxResults,
Guid? groupId,
bool? includeSubGroups,
DateTime? olderThan,
DateTime? newerThan)
{
using (IRepository<Template> templates = Context.Current.Create<IRepository<Template>>())
{
var selectedTemplates = templates.
Where(t => t.Account.Id == accountId).
Where(groupId.HasValue, t => t.Group.Id == groupId.Value).
Where(!groupId.HasValue && includeSubGroups.HasValue &&
!includeSubGroups.Value, t => t.Group == null).
Where(olderThan.HasValue, t => t.Created < olderThan.Value).
Where(newerThan.HasValue, t => t.Created > newerThan.Value).
Take(maxResults.HasValue, maxResults.Value).
Skip(startIndex.HasValue, startIndex.Value - 1);
return selectedTemplates.ToList();
}
}