c# - EF Core 全局查询过滤器复杂表达式
问题描述
我正在尝试在我的应用程序中为租户实现全局查询过滤器。我AssessmentModels
可以拥有多个所有者,这些所有者来自我无法完全控制的第 3 方,但可以根据需要进行调整。(并且可以在我保存到我的数据库之前进行操作)现在,Owners
存储为分号分隔的字符串(例如,team1;team2
)。
我想出了以下适用于选择数据的方法,但不适用于全局查询过滤器:
private Expression<Func<AssessmentModel, bool>> GetAssessmentFilter()
{
// The lambda parameter.
var assessmentParameter = Expression.Parameter(typeof(AssessmentModel), "a");
// Build the individual conditions to check against.
var orConditions = _adminTeamNames
.Select(keyword => (Expression<Func<AssessmentModel, bool>>)(a => EF.Functions.Like(a.Owners, $"%{keyword}%")))
.Select(lambda => (Expression)Expression.Invoke(lambda, assessmentParameter))
.ToList();
// Combine the individual conditions to an expression tree of nested ORs.
var orExpressionTree = orConditions
.Skip(1)
.Aggregate(
orConditions.First(),
(current, expression) => Expression.OrElse(expression, current));
// Build the final predicate (a lambda expression), so we can use it inside of `.Where()`.
var predicateExpression = (Expression<Func<AssessmentModel, bool>>)Expression.Lambda(
orExpressionTree,
assessmentParameter);
return predicateExpression;
}
所以,
var result = db.Assessments.Where(predicateExpression).ToList();
工作,但modelBuilder.Entity<AssessmentModel>().HasQueryFilter(predicateExpression);
给出了错误:
System.InvalidOperationException : The LINQ expression 'DbSet<AssessmentModel>()
.Where(a => Invoke(a => value(DbFunctions).Like(a.Owners, "%Los%"), a)
|| Invoke(a => value(DbFunctions).Like(a.Owners, "%Atl%"), a)
)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
解决方案
AFAIK EF Core 不太擅长翻译调用表达式。尝试用您的自定义参数表达式(即assessmentParameter
)手动替换 build lambda 的参数:
var orConditions = _adminTeamNames
.Select(keyword => (Expression<Func<AssessmentModel, bool>>)(a => EF.Functions.Like(a.Owners, $"%{keyword}%")))
.Select(lambda => new ReplacingExpressionVisitor(lambda.Parameters, new []{assessmentParameter}).Visit(lambda.Body))
.ToList();
推荐阅读
- c++ - 使用 opencv/c++ 将像素转换为 mm --> 两点之间的距离
- python - 如何在 matplotlib 图中添加点图例?
- c - 比较函数作为稍后使用的参数
- java - Java:当事件实际上丢失时,如何对收集事件消息的类设置时间限制
- php - 在 PHP,laravel 中更改索引数组
- react-native - 如何使用 React Native Navigation。像堆栈导航
- date - 年初至今在 DAX 中超过一年
- asp.net-core - 无法在 NGINX 代理后面的 Blazor 服务器上加载静态文件
- javascript - 控制台日志上的警告 sdk angularfire
- freemarker - Freemarker 迭代地图列表,例如:地图
> 带有类似菜单子页面的模式