Выражение странного поведения <Func>в методе EfCore HasQueryFilter v2.2 (проблема рефакторинга) - PullRequest
1 голос
/ 27 января 2020

У меня есть QueryFilter в моем AppDbContext EfCore 2.2:

builder.Entity<MessageReceiver> ().HasQueryFilter (
    (q) => (q.ReciverId == _uai.LoggedInUserId) || 
           (q.Message.SenderId == _uai.LoggedInUserId));

этот код работает нормально, потому что я внедрил пользовательскую службу (_uai) для проверки информации о вошедшем в систему пользователе в мой AppDbContext.

   public class AppDbContext : DbContext {
      private readonly IUserAccessInfoService _uai;

      public AppDbContext (DbContextOptions<AppDbContext> options, IUserAccessInfoService userAccessInfo) : base (options) {
         _uai = userAccessInfo;
      }

но я не могу реорганизовать этот код и перенести все выражение в мой сервис! после рефакторинга этого кода в сервис '_uai' я использую это как:

builder.Entity<MessageReceiver> ().HasQueryFilter (_uai.GetMessageQueryFilter ());

и в моем сервисе 'uai' я рефакторинг выражения:

// UserAccessInfoService ....

public Expression<Func<MessageReceiver, bool>> GetMessageQueryFilter () {
         return (q) =>
            (q.ReciverId == LoggedInUserId) || 
            (q.Message.SenderId == LoggedInUserId);
      }

// this way loggedInUser is null in runtime

действительно имеет выражения некоторые встроенные возможности кеша? проблема в том, что EFCore не использует внедренные служебные значения, когда я рефакторинг этого кода и LoggedInUserId является нулевым после рефакторинга. я думаю, что есть какое-то кэширование, которое efcore использует для своих выражений.

1 Ответ

2 голосов
/ 28 января 2020

Выражения, используемые в глобальных фильтрах запросов, являются специальными. В частности, они оцениваются только один раз , за исключением частей, которые поступают из поля, свойства или метода DbContext (как в исходном коде).

Это частично объясняется в EF Core Global Query Fiters пример документации:

Совет

Обратите внимание на использование поля уровня экземпляра DbContext: _tenantId используется для установить текущий арендатор. Фильтры уровня модели будут использовать значение из правильного экземпляра контекста (то есть экземпляра, выполняющего запрос).

Я бы хотел, чтобы они были более явными и объяснили это поведение в документирование, а не подсказка к примеру, потому что на самом деле это единственный способ получить динамически оцениваемый фильтр.

С учетом сказанного сохраните исходный код как есть или используйте другой способ рефакторинга в случае, если это необходимо в нескольких местах - интерфейс / базовый класс / EF.Property или составление выражения вручную, чтобы связать выражения ReceiverId и SenderId, но при этом сравнить их с this._uai.LoggedInUserId.

...