Сложное выражение фильтра глобальных запросов EF Core

#c# #entity-framework-core #.net-6.0 #ef-core-6.0

Вопрос:

Я пытаюсь реализовать глобальный фильтр запросов для аренды в своем приложении. У меня AssessmentModels может быть несколько владельцев, владельцы приходят от третьей стороны, которую я не полностью контролирую, но могу настроить по мере необходимости. (И может манипулировать, прежде чем я сохраню в своей базе данных) Прямо сейчас Owners они хранятся в виде строки, разделенной точкой с запятой (например, team1;team2 ).

Я придумал следующее, которое работает для выбора данных, но не работает для глобального фильтра запросов:

 private Expressionlt;Funclt;AssessmentModel, boolgt;gt; GetAssessmentFilter() {  // The lambda parameter.  var assessmentParameter = Expression.Parameter(typeof(AssessmentModel), "a");  // Build the individual conditions to check against.  var orConditions = _adminTeamNames  .Select(keyword =gt; (Expressionlt;Funclt;AssessmentModel, boolgt;gt;)(a =gt; EF.Functions.Like(a.Owners, $"%{keyword}%")))  .Select(lambda =gt; (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) =gt; Expression.OrElse(expression, current));    // Build the final predicate (a lambda expression), so we can use it inside of `.Where()`.  var predicateExpression = (Expressionlt;Funclt;AssessmentModel, boolgt;gt;)Expression.Lambda(  orExpressionTree,  assessmentParameter);   return predicateExpression; }  

Так, var result = db.Assessments.Where(predicateExpression).ToList(); работает, но modelBuilder.Entitylt;AssessmentModelgt;().HasQueryFilter(predicateExpression); выдает ошибку:

 System.InvalidOperationException : The LINQ expression 'DbSetlt;AssessmentModelgt;() .Where(a =gt; Invoke(a =gt; value(DbFunctions).Like(a.Owners, "%Los%"), a)  || Invoke(a =gt; 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.  

Ответ №1:

Ядро AFAIK EF не очень хорошо переводит выражения вызова. Попробуйте вручную заменить параметр построения лямбды вашим пользовательским выражением параметра (т. е. assessmentParameter ) :

 var orConditions = _adminTeamNames  .Select(keyword =gt; (Expressionlt;Funclt;AssessmentModel, boolgt;gt;)(a =gt; EF.Functions.Like(a.Owners, $"%{keyword}%")))  .Select(lambda =gt; new ReplacingExpressionVisitor(lambda.Parameters, new []{assessmentParameter}).Visit(lambda.Body))  .ToList();  

Комментарии:

1. Вот и все-спасибо!