'Entity Framework Core Global Dynamic Query Filter
we are using ef core 3.1 And we want to use dynamic query filter, I tried sample implementation but did not work correctly we expected, filtering always same tenant id,i tried to explain at below
public class TestDbContext : DbContext
{
public DbSet<TenantUser> TenantUsers { get; set; }
private readonly ITenantProvider _tenantProvider;
private Guid? TenantId => _tenantProvider.TenantId;
public TestDbContext (DbContextOptions<TestDbContext > options, ITenantProvider tenantProvider) : base(options)
{
_tenantProvider = tenantProvider;
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<TenantUser>()
.HasQueryFilter(p => EF.Property<Guid>(p, "TenantId") == TenantId);
}
}
ITenantProvider returns TenantId from HttpContext headers
this code filtering always same tenant id from coming first request
Update:
public class TenantProvider : ITenantProvider
{
private readonly IHttpContextAccessor _httpContextAccessor;
public TenantProvider(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public Guid? TenantId
{
get
{
if (_httpContextAccessor.HttpContext.Request.Headers.TryGetValue(HeaderNames.TenantId, out var tenantId) &&
Guid.TryParse(tenantId, out Guid parsedTenantId))
{
return parsedTenantId;
}
return null;
}
}
}
For example First Request TenantId = 60000000-0000-0000-0000-000000000000 This filter => 60000000-0000-0000-0000-000000000000
Second Request TenantId = 10000000-0000-0000-0000-000000000000 This filter => 60000000-0000-0000-0000-000000000000
Solution 1:[1]
We tried something similar like that a few years ago. Main problem is here that OnModelCreating method only triggered once. So HasQueryFilter works once and gets the current tenant id from provider and it applies to all queries the same tenant id.
Solution 2:[2]
You should also implement a custom IModelCacheKeyFactory
public class MyModelCacheKeyFactory : IModelCacheKeyFactory
{
public object Create(DbContext context)
{
if (context is TestDbContext testDbContext)
{
return (context.GetType(), testDbContext.TenantId);
}
return context.GetType();
}
}
And then, you need to replace like this
var builder = new DbContextOptionsBuilder<TestDbContext>();
builder.ReplaceService<IModelCacheKeyFactory, MyModelCacheKeyFactory>();
var context = new TestDbContext(builder.Options);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Ahmet Selman ?ener |
| Solution 2 | Richard |
