Is it possible to write the below in one line?
//Create a Global Filter for the TenantId property.
modelBuilder.Entity<Item>().HasQueryFilter(b => EF.Property<int>(b, "TenantId") == this._appUserProvider.CurrentTenantId);
modelBuilder.Entity<Invite>().HasQueryFilter(b => EF.Property<int>(b, "TenantId") == this._appUserProvider.CurrentTenantId);
I have tried an Interface for Item and Invite, but EF threw an error saying it must be a reference type.
I also tried a base class, but I don't want to change the base tables which seemed to be required to make that work.
Any other options?
Global query filters are LINQ query predicates applied to Entity Types in the metadata model (usually in OnModelCreating ). A query predicate is a boolean expression typically passed to the LINQ Where query operator. EF Core applies such filters automatically to any LINQ queries involving those Entity Types.
Global filters are used to control the display of one or more reports in a single portal page or in a dashboard. For example, a global filter can be on a report that contains only a prompt or prompt controls. This allows for a single selection to drive a number of reports at once.
To filter data, use linq. You can not use Filter property of BindingSource when the underlying list is BindingList<T> ; Only underlying lists that implement the IBindingListView interface support filtering. To remove filter, just set the data source of your binding source to the local storage of your entities again.
Let say your entities implement the following interface:
public interface ITenantEntity
{
int TenantId { get; set; }
}
The most important thing when using common code to configure multiple entities via fluent API is to use the real entity type when calling modelBuilder.Entity<TEntity>()
. Using a base class will introduce EF inheritance, and interface will simply generate exception.
The easiest solution IMO is to put the common code in a generic method and call it via reflection.
Start by creating a constrained generic instance method in your derived DbContext
class containing the desired fluent configuration:
void ConfigureTenantFilter<TEntity>(ModelBuilder modelBuilder)
where TEntity : class, ITenantEntity
{
modelBuilder.Entity<TEntity>()
.HasQueryFilter(e => e.TenantId == this._appUserProvider.CurrentTenantId);
}
Then use the following snippet at the end of your OnModelCreating
override (after all entity types are discovered):
var configureTenantMethod = GetType().GetTypeInfo().DeclaredMethods.Single(m => m.Name == nameof(ConfigureTenantFilter));
var args = new object[] { modelBuilder };
var tenantEntityTypes = modelBuilder.Model.GetEntityTypes()
.Where(t => typeof(ITenantEntity).IsAssignableFrom(t.ClrType));
foreach (var entityType in tenantEntityTypes)
configureTenantMethod.MakeGenericMethod(entityType.ClrType).Invoke(this, args);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With