We include multi-tenancy implementation in the template via DbContextQueryFilterExtensions and PostProcessEntitiesOnSaveInterceptor.
Multi tenancy roughly means that different groups of users see different data. It could be that:
- Every user has his own set of data (e.g. ToDo app)
- Every user belongs to some Organisation (tenant), and users within Organisation see the same data, but user in different Organisations never share the data (e.g. different Organisations in AzureDevOps)
EFCore has support for such kind of data sharing out of the box via Query Filters.
Usually it's implemented so that EVERY database Entity has a special column, which describes the Tenant entity belongs to (e.g. OwnerId
for 1st scenario, or TenantId
for 2nd scenario).
EFCore is then configured with a QueryFilter so that EF only returns entities with the same OwnerId
(or TenantId
) as the currently logged-in user has.
In Template it's integrated like this:
protected override void OnModelCreating(ModelBuilder builder)
{
builder.SetupQueryFilter<IOwnedEntity>(
(x) => CurrentOwnerId == null || x.OwnerId == CurrentOwnerId
);
}
Also it makes sense to automatically set this OwnerId
(or TenantId
) field whenever an entity is saved to the DB.
It could be done with help of PostProcessEntitiesOnSaveInterceptor:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.AddInterceptors(
new PostProcessEntitiesOnSaveInterceptor<IOwnedEntity, TemplateAppDbContext>(
(entity, context) =>
{
entity.SetOwnerIdUnsafe(context.CurrentOwnerId);
}
)
);
}
it will call the passed action when IOwnedEntity
is saved.