I have a REST WebAPI using EntityFramework
database first. All code is generated off the EDMX
file, entities, repository classes and API controllers etc.
I have added some filtering functionality which allows users to add conditions via the query string that translate to LinqKit PredicateBuilder / Linq
expressions that filter results when hitting the db.
e.g. /api/Users?FirstName_contains=Rog
This will return all users with 'Rog' in the User.FirstName
member. This uses PredicateBuilder
to dynamically build an appropriate Linq
expression to then use as a Where
clause against the DbSet
.
For example:
var fieldName = "FirstName";
var value = "Rog";
var stringContainsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var parameter = Expression.Parameter(typeof(User), "m");
var fieldAccess = Expression.PropertyOrField(parameter, fieldName);
var fieldType = typeof(User).GetProperty(fieldName, BindingFlags.IgnoreCase | BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public).PropertyType;
var expression = Expression.Lambda<Func<User, bool>>(Expression.Call(fieldAccess, stringContainsMethod, Expression.Constant(value, fieldType))
, parameter)
var andPredicate = PredicateBuilder.True<User>();
andPredicate = andPredicate.And(expression);
var query = Db.Users
.AsQueryable()
.AsExpandable()
.Where(andPredicate);
Now the problem. I want the client to be able to match results based on a composition of members.
e.g. /api/Users?api_search[FirstName,LastName]=Rog
i.e. search first name + last name
for matches of 'Rog', so I could search for 'Roger Sm' and get a result for first name = Roger and last name = Smith.
If I was to query the DbSet
using fluent it would look like:
users.Where(u => (u.FirstName + " " + u.LastName).Contains("Rog"));
What I am struggling with is creating a predicate / linq
expression that will handle the concatenation of string members FirstName + " " + LastName
dynamically.