Sto usando il metodo di estensione HasQueryFilter EF Core, che si trova all'interno del metodo OnModelCreating.
Inserisco l'ID utente in DbContext utilizzando un servizio e quindi applicando l'ID utente al filtro di query. Per la prima volta, quando viene eseguito OnModelCreating, funziona come previsto. Ma quando cambio l'utente e trasferisco un altro ID utente a DbContext, il filtro di query non è influenzato come ovvio perché OnModelCreating non viene chiamato questa volta.
Un piccolo background dell'app: è un progetto API 2.2 di base che autentica gli utenti utilizzando il token JWT. Compilare le rivendicazioni utente e inizializzare il servizio di autenticazione immesso utilizzando il JWT, quindi per ogni chiamata all'API l'ID utente può essere diverso, quindi il filtro di query dovrebbe funzionare su diversi ID utente.
Codici di esempio di seguito:
public class SqlContext : DbContext
{
private readonly IAuthService _authService;
public SqlContext(DbContextOptions options, IAuthService authService) : base(options)
{
_authService = authService;
}
public DbSet<Device> Devices { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Device>().HasQueryFilter(p => !p.IsDeleted && p.ManufacturerId == _authService.ManufacturerId);
}
}
Come viene inizializzato DbContext.
services.AddDbContextPool<TContext>(o =>
o.UseSqlServer(configuration["Settings:SqlServer:DefaultConnection"],
b =>
{
b.MigrationsAssembly(configuration["Settings:SqlServer:MigrationAssembly"]);
b.CommandTimeout(60);
b.EnableRetryOnFailure(2);
})
.ConfigureWarnings(warnings =>
{
warnings.Throw(RelationalEventId.QueryClientEvaluationWarning);
}))
.AddTransient<TContext>();
Finalmente risolto.
Poiché il filtro funzionava, ma non veniva aggiornato dopo la prima richiesta del modello. Il motivo era che EF stava memorizzando nella cache il modello creato. Quindi, ho dovuto implementare l' IModelCacheKeyFactory per acquisire i diversi modelli come per i filtri.
internal class DynamicModelCacheKeyFactory : IModelCacheKeyFactory
{
public object Create(DbContext context)
{
if (context is SqlContext dynamicContext)
{
return (context.GetType(), dynamicContext._roleCategory);
}
return context.GetType();
}
}
E collegato al contesto come questo.
protected override void OnConfiguring(DbContextOptionsBuilder builder)
{
base.OnConfiguring(builder);
builder.ReplaceService<IModelCacheKeyFactory, DynamicModelCacheKeyFactory>();
}