Currently (starting with EF Core 2.0.0) dynamic global query filtering is quite limited. This only works if the dynamic part is provided by the direct property of the target derived class DbContext (or one of its base derived classes DbContext ). In the same way as in the example of query filters at the model level from the documentation. Exactly this way - without method calls, without nested methods for accessing properties - only a context property. This is somehow explained in the link:
Note the use of the instance level property of DbContext : TenantId . Model level filters will use the value from the correct context instance. i.e. the one that is executing the request.
For this to work in your scenario, you must create a base class similar to the following:
public abstract class TenantDbContext : DbContext { protected ITenantProvider TenantProvider; internal int TenantId => TenantProvider.GetId(); }
extracts your context class from it and somehow injects an instance of TenantProvider into it. Then change the TenantEntityConfigurationBase class to get TenantDbContext :
internal abstract class TenantEntityConfigurationBase<TEntity, TKey> : EntityConfigurationBase<TEntity, TKey> where TEntity : TenantEntityBase<TKey> where TKey : IEquatable<TKey> { protected readonly TenantDbContext Context; protected TenantEntityConfigurationBase( string table, string schema, TenantDbContext context) : base(table, schema) { Context = context; } protected override void ConfigureFilters( EntityTypeBuilder<TEntity> builder) { base.ConfigureFilters(builder); builder.HasQueryFilter( e => e.TenantId == Context.TenantId); } protected override void ConfigureRelationships( EntityTypeBuilder<TEntity> builder) { base.ConfigureRelationships(builder); builder.HasOne( t => t.Tenant).WithMany().HasForeignKey( k => k.TenantId); } }
and everything will work as expected. And remember, the type of the Context variable must be a derived DbContext class - replacing it with an interface will not work.
Update for 2.0.1 : as @Smit pointed out in the comments, v2.0.1 removed most of the restrictions - now you can use methods and auxiliary properties.
However, another requirement has been introduced - a dynamic expression must be based on DbContext .
This requirement violates the above solution, because the root of the expression is the TenantEntityConfigurationBase<TEntity, TKey> , and creating such an expression outside of DbContext not so simple due to the lack of compile-time support for generating constant expressions.
This problem can be solved with the help of some low-level expression manipulation methods, but in your case it would be easier to move the filter creation to the generic TenantDbContext instance TenantDbContext and call it from the entity configuration class.
Here are the modifications:
TenantDbContext Class:
internal Expression<Func<TEntity, bool>> CreateFilter<TEntity, TKey>() where TEntity : TenantEntityBase<TKey> where TKey : IEquatable<TKey> { return e => e.TenantId == TenantId; }
TenantEntityConfigurationBase & lt; TEntity, TKey> class:
builder.HasQueryFilter(Context.CreateFilter<TEntity, TKey>());