我正在尝试创建一个通用过滤类,它将接收属性访问器并检查它是否在允许的值范围内。所以过滤器的签名是:
class PropertyFilter<TItem, TProperty>
{
PropertyFilter(Expression<Func<TItem, TProperty>> accessor, IEnumerable<TProperty> allowedValues);
IQueryable<TItem> Filter(IQueryable<TItem> items);
}
和使用
var filter = new PropertyFilter<Entity, string>(e => e.Name, new [] { "NameA", "NameB" });
await filter.Filter(dbContext.Entities).ToListAsync();
事情必须是 IQueryable
兼容,所以我需要编写一个表达式。来自 x => x.Property
形式的表达式我需要创建一个表达式 Expression<Func<TItem, bool>>
相当于x => allowedValues.Contains(x.Property)
。从我所看到的来看,我基本上可以使用访问者等对表达式执行任何操作,但我不知道将表达式转换为 SQL 的规则是什么,以及我不能做什么或破坏它,而且该用例似乎太简单了,无法保证需要那么多代码来实现我自己的访问者并测试所有这些。有没有一种简单的方法可以做到这一点,或者可能有一个可靠的库已经解决了这个问题并且与 .NET Core 3.0 和 EF Core 3.0 预览版兼容?
最佳答案
首先,EF Core 3.0 预览版不像任何预览版(测试版)软件那样可靠。此外,目前他们正在重写 LINQ 查询表达式树翻译,因此它非常不稳定,很多东西都不起作用,即使它们在最后一个稳定的 EF Core 2.x 中工作。
因此,此时尝试解决这些问题是没有意义的。最好保留最后一个稳定的 2.x 并等待官方 3.0 发布。
无论如何,你所要求的叫做表达合成,并且有很多帖子如何做到这一点,包括我写的一些。重要的是使用参数替换技术而不是Expression.Invoke
,因为后者在3.0之前的版本中工作,但众所周知前者可以与所有查询提供程序一起工作。
所以你需要一个像这样的小型辅助表达式实用程序
public static partial class ExpressionUtils
{
public static Expression ReplaceParameter(this Expression expression, ParameterExpression source, Expression target)
=> new ParameterReplacer { source = source, target = target }.Visit(expression);
class ParameterReplacer : ExpressionVisitor
{
public ParameterExpression source;
public Expression target;
protected override Expression VisitParameter(ParameterExpression node)
=> node == source ? target : node;
}
}
然后是一个辅助表达式的编写方法,如下所示:
public static partial class ExpressionUtils
{
public static Expression<Func<TOuter, TResult>> Select<TOuter, TInner, TResult>(
this Expression<Func<TOuter, TInner>> innerSelector,
Expression<Func<TInner, TResult>> resultSelector)
=> Expression.Lambda<Func<TOuter, TResult>>(
resultSelector.Body.ReplaceParameter(resultSelector.Parameters[0], innerSelector.Body),
innerSelector.Parameters);
}
有了这些帮助器,相关表达式的实现(幸运的是在 3.0 预览版中有效)将变得简单:
return accessor.Select(value => allowedValues.Contains(value));
以这种方式编写表达式的好处是,结果与编译时的结果完全相同,因此获得支持的机会更大。
关于c# - 将属性访问表达式转换为谓词表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57311417/