合并属性选择器表达式树和值以创建EF过滤的谓词 - 从lambda选择器和值创建过滤器

Jas*_*yne 3 c# linq lambda entity-framework expression-trees

给定一个具有任意属性的简单类(讨论可以说是Id,Name和Description)

并且给定该类的实例,我想通过指定要匹配的属性来在数据库中找到匹配的条目

我试图在这方面做一些类似于EF的AddOrUpdate方法的事情,但我需要实体返回给我进行进一步处理.

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;
 }
Run Code Online (Sandbox Code Playgroud)

这给了我传入的对象中属性的值,但我现在需要将该值与传入的表达式组合并将其传递给数据库集.

IE浏览器,我试图有效运行的代码是 set.FirstOrDefault(x=>x.Name==valueToFind)如何把matchon表达式(包含x=>x.Name),并结合起来,与将==valueToFind得到x=>x.Name==valueToFind来自他们?

如何构建组合表达式?(我意识到上面的"字符串"代码是完全错误的,但我试图了解我需要该函数做什么,但我不知道那个语法会是什么样子.)

对于手动编码的示例,只需传入带有值集的硬编码lambda就足够了,但是我的用例包括遍历一组对象并找到每个对象的匹配,因此在运行时之前不会知道该值,并且该方法必须对任意类型和各种属性起作用,因此我也不能对属性名称进行硬编码.

Jot*_*aBe 6

如果你有一个属性选择器和一个要比较的值,你可以得到一个这样的表达式树:

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;
}
Run Code Online (Sandbox Code Playgroud)

样品用法:

var comparer = GetComparer<Person, string>(p => p.Name, "John");
var persons = Person.GetPersons();
var john = persons.FirstOrDefault(comparer);
Run Code Online (Sandbox Code Playgroud)