Patrick Szalapski Patrick Szalapski - 21 days ago 6
C# Question

How can I build logic upon supplied logic in a LINQ-to-Entities Where expression?

I often come across, in LINQ for Entity Framework, a pattern where I add a

.Where
clause if a string value is specified, like:

IQueryable<Foo> query = Foos.AsQueryable()
if (!string.IsNullOrWhitespace(nameFilter)) query = query.Where(x => x.Name == name);
if (!string.IsNullOrWhitespace(addressFilter) != null) query = query.Where(x => x.Address == addressFilter );
if (!string.IsNullOrWhitespace(cityFilter) != null) query = query.Where(x => x.City == cityFilter );
// ...


I wanted to clean this up and avoid repeating the filter. I thought I could create an extension method:

public static IQueryable<T> WhereEqualIfSpecified<T>(
this IQueryable<T> query,
Expression<Func<T, string>> fieldDelegate,
string filterValue)
{
return string.IsNullOrWhiteSpace(filterValue)
? query
: query.Where(x => fieldDelegate(x) == filterValue); // not valid, see question below
}


So that I can instead change my code to:

IQueryable<Foo> query = Foos.AsQueryable()
.WhereEqualIfSpecified(x => x.Name, nameFilter)
.WhereEqualIfSpecified(x => x.Address, addressFilter)
.WhereEqualIfSpecified(x => x.City, cityFilter)
// ...
;


But I found that, in the
WhereEqualIfSpecified
method above,
fieldDelegate
must be compiled to a
Func()
to be invoked against the entity source, which ruins the point of doing these steps, which would be executed in the database in my original code.

I am missing the last step of how to create a new
Expression
from
fieldDelegate
that can do a comparison, rather than just returning the string value. Will this approach work? How do I make the necessary
Expression
in
WhereEqualIfSpecified
to allow LINQ-to-Entities to execute it later?

Answer

What you're trying to do here is to compose expressions. Expressions, unlike delegates, are a bit tricker to compose. Here is one implementation of how to compose expressions. Once you have that Compose method you can write your extension method as:

public static IQueryable<T> WhereEqualIfSpecified<T>(
    this IQueryable<T> query,
    Expression<Func<T, string>> fieldExpression,
    string filterValue)
{
    return string.IsNullOrWhiteSpace(filterValue) 
        ? query 
        : query.Where(fieldExpression.Compose(value => value == filterValue);
}