Combine property selector selection tree and value to create predicate for filtering EF - create filter from lambda selector and value
For a simple class with arbitrary properties (for discussion, you can specify Id, Name and Description)
and given an instance of this class, I want to find matching records in the database by specifying a property to match
I'm trying to do something in this regard, similar to the AddOrUpdate method for EF, but I need an entity returned to me for further processing.
var match = new SomeClass{Name="Whatever"};
var found = Context.SomeClass.Find(x=>x.Name, match);
public static T Find<T>(this DbSet<T> set, Expression<Func<T, object>> matchOn, T matchAgainst) where T : class {
var func = matchOn.Compile();
var valueToFind = func(matchAgainst);
var combinedExpression = //matchon + "=" + valueToFind;
var found = set.FirstOrDefault(combinedExpression);
return found;
}
This gives me the value of the property in the passed object, but I now need to concatenate that value with the passed in expression and pass it to the db set.
IE, the code I'm really trying to run is set.FirstOrDefault(x=>x.Name==valueToFind)
How to take an expression matchon
(which contains x=>x.Name
) and combine that with ==valueToFind
to get from itx=>x.Name==valueToFind
How do I create a combined expression? (I realize that the "string" code above is completely wrong, but I was trying to figure out what I need for this function, but I don't know what this syntax would look like.)
For hand-coded examples, it would be enough to just pass in a hardcoded lambda with a set value, but my use case involves starting a collection of objects and looking for a match for each one, so the value won't be known until execution and the method must work against arbitrary types and various properties, so I can't hardcode the property name as well.
source to share
If you have a property selector and a value to compare, you can get an expression tree like this:
public static Func<TEntity, bool> GetComparer<TEntity,TProperty>(
Expression<Func<TEntity,TProperty>> selector, TProperty value)
{
var propertyRef = selector.Body;
var parameter = selector.Parameters[0];
var constantRef = Expression.Constant(value);
var comparer
= Expression.Lambda<Func<TEntity, bool>>
(Expression.Equal(propertyRef, constantRef), parameter)
.Compile();
return comparer;
}
Sample usage:
var comparer = GetComparer<Person, string>(p => p.Name, "John");
var persons = Person.GetPersons();
var john = persons.FirstOrDefault(comparer);
source to share