组合 属性 选择器表达式树和值以创建用于 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);
给定一个具有任意属性的简单 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);