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

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

给定一个具有任意属性的简单 class(讨论时可以说 Id、名称和描述)

并给定 class 的一个实例,我想通过指定 属性 来匹配

在数据库中找到匹配的条目

我正在尝试在这方面做一些类似于 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;
 }

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

IE,我有效地尝试 运行 的代码是 set.FirstOrDefault(x=>x.Name==valueToFind) 如何获取 matchon 表达式(包含 x=>x.Name)并将其与==valueToFind 从他们那里得到 x=>x.Name==valueToFind

如何构建组合表达式? (我意识到上面的 "string" 代码是完全错误的,但我试图了解我需要该函数执行的操作,但我不知道该语法是什么样的。)

对于手动编码的示例,只需传入带有值集的硬编码 lambda 就足够了,但我的用例涉及 运行遍历对象集合并为每个对象找到匹配项,因此直到 运行 时间才会知道该值,并且该方法必须针对任意类型和各种属性起作用,因此我也无法对 属性 名称进行硬编码。

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

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

示例用法:

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