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.

+3


source to share


1 answer


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);

      

+6


source







All Articles