EF Core HasQueryFilter works for only the first value in filter expression

c# ef-core-2.2 entity-framework entity-framework-core filter

Question

I am using EF Core HasQueryFilter extension method, which is inside the OnModelCreating method.

I am injecting the user id into the DbContext using a service and then applying the userId to the query filter. For the first time when the OnModelCreating is executed it works fine as expected. But when I change the user and pass a different userId to the DbContext then query filter is not affected as obvious because the OnModelCreating is not called this time.

A little background of the App: It's a core 2.2 API project which authenticates users using the JWT token. I populate the user claims and initialize the injected auth service using the JWT, so for every call to the API the userId can be different hence query filter should work on different userIds.

Example codes below:

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);
    }
}

How the DbContext is initialized.

 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>();
1
3
2/22/2019 10:26:55 PM

Popular Answer

Finally solved it.

As the filter was working, but it was not getting updated once the model was created after first request. The reason was that EF was caching the created model. So, I had to implement the IModelCacheKeyFactory in order to capture the different models as per the filters.

internal class DynamicModelCacheKeyFactory : IModelCacheKeyFactory
{
    public object Create(DbContext context)
    {
        if (context is SqlContext dynamicContext)
        {
            return (context.GetType(), dynamicContext._roleCategory);
        }
        return context.GetType();
    }
}

And attached it to the context like this.

protected override void OnConfiguring(DbContextOptionsBuilder builder)
    {
        base.OnConfiguring(builder);

        builder.ReplaceService<IModelCacheKeyFactory, DynamicModelCacheKeyFactory>();
    }
2
2/25/2019 8:55:22 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow