简体   繁体   中英

Combine property selector expression tree and value to create a predicate for EF filtering - create filter from lambda selector and value

Given a simple class with arbitrary properties (for discussion lets say Id, Name, and Description)

and given an instance of that class, I want to find matching entries in the database by specifying the property to match

I'm trying to do something in this respect similar to the AddOrUpdate method of EF, but I need the 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;
 }

That gives me the value of the property in the passed in object, but I need to now combine that value with the passed in expression and pass it to the db set.

IE, the code I'm effectively trying to run is set.FirstOrDefault(x=>x.Name==valueToFind) How do I take the matchon expression (which contains x=>x.Name ) and combine that with the ==valueToFind to get the x=>x.Name==valueToFind from them?

How do I build the combined expression? (I realize the "string" code above is completely wrong, but I was trying to get across what I need the function to do, but I have no idea what that syntax would look like.)

For manually coded examples, it would be easy enough just to pass in a hardcoded lambda with the value set, but my use case involves running through a collection of objects and finding the match for each one, so the value will not be known until runtime, and the method must work against arbitrary types and various properties, so I can't hardcode the property name either.

If you have a property selector, and a value to compare to, 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);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM