Реализации MultiTenancy и HasQueryFilter для глобальной фильтрации Entity Framework Core

Есть две основные статьи, по которым пытаюсь решить задачу:

В каждой из статей присутствует код такого вида:

public class MultitenancyContext(string tenantId) : DbContext
{
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>().HasQueryFilter(b => b.TenantId == tenantId);
    }
}

Или

public ContactContext(DbContextOptions<ContactContext> opts, ITenantService service) : base(opts)
    => _tenant = service.Tenant;

protected override void OnModelCreating(ModelBuilder modelBuilder)
    => modelBuilder.Entity<MultitenantContact>().HasQueryFilter(mt => mt.Tenant == _tenant);

Пример моей реализации:

public partial class AppDbContext(DbContextOptions<AppDbContext> options, ICurrentUserContext currentUserContext) : DbContext(options)
{
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.ApplyAssemblyConfigurations();

        if (currentUserContext.CompanyId is not null)
        {
            modelBuilder.Entity<UserEntity>().HasQueryFilter(tenant => tenant.CompanyId == currentUserContext.CompanyId);
        }
    }
}

В чём проблема? При запуске проекта этот код выполняется (логично). Но если я изменю текущего пользователя (войду под другим аккаунтом) это работать уже не будет для пользователя из другой компании. На сколько я изучил вопрос, OnModelCreating выполняется только раз при старте программы, даже если у меня сам DbContext зарегистрирован как Scoped сервис:

var connectionStringName = GlobalConstants.Db.ConnectionStringName;
var connectionString = configuration.GetConnectionString(connectionStringName);

services.AddDbContext<AppDbContext>(option => option.UseNpgsql(connectionString).LogTo(Console.WriteLine, LogLevel.Information));

Вопрос в том, как правильно тогда это реализовать? Я что-то упускаю?

UPD1:

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

UPD2:

Вот такой вариант не работает:

public partial class AppDbContext : DbContext
{
    private readonly int? _currentCompanyId;

    public AppDbContext(DbContextOptions<AppDbContext> options, ICurrentUserContext currentUserContext) : base(options)
    {
        _currentCompanyId = currentUserContext.CompanyId;
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.ApplyAssemblyConfigurations();

        if (_currentCompanyId is not null)
        {
            modelBuilder.Entity<UserEntity>().HasQueryFilter(tenant => tenant.CompanyId == _currentCompanyId);
        }
    }
}

Пробовал в связке с различными типами регистрации DbContext:

services.AddDbContextFactory<TContext>(options => options.UseNpgsql(connectionString).LogTo(Console.WriteLine, LogLevel.Information));

services.AddDbContext<TContext>(option => option.UseNpgsql(connectionString).LogTo(Console.WriteLine, LogLevel.Information));

UPD3:

Следующий варианты хранения значений так же не работают:

public int? CurrentCompanyId { get; set; }
public ICurrentUserContext CurrentUserContext { get; set; }

UPD4:

На основе статьи "Чередование между несколькими моделями с одинаковым типом DbContext" я создал свой вариант кеш-фабрики:

public sealed class AppContextCacheKeyFactory : IModelCacheKeyFactory
{
    public object Create(DbContext context, bool designTime)
    {
        AppDbContext? dbContext = context as AppDbContext;
        
        if (dbContext is null)
        {
            return dbContext.GetType();
        }

        return (context.GetType(), dbContext.CurrentUserContext.CompanyId, designTime);
    }
}

И изменил свою регистрацию DbContext:

services.AddDbContextFactory<TContext>(options => options
    .UseNpgsql(connectionString)
    .LogTo(Console.WriteLine, LogLevel.Information)
    .ReplaceService<IModelCacheKeyFactory, AppContextCacheKeyFactory>()
);

При каждом обращении срабатывает строчка return (context.GetType(), dbContext.CurrentUserContext.CompanyId, designTime);, что обозначает, что создаётся и добавляется в кеш новый DbContext. Но программа так и не попадает в метод OnModelCreating. Более того, при анализе лога запроса, я так и не видел AND COMPANY_ID = ... или чего-то подобного.


Ответы (0 шт):