I am referencing these docs: https://abp.io/docs/latest/framework/data/entity-framework-core#controlling-the-multi-tenancy
I would like to ensure that some entities always uses the host connection string, even if I am in a tenant context.
Based on the documentation, this can be done on the DbContext level, where all DbSet<Entity> defined in that context will be only using the host connection string.
Question is if there is a way to define this [IgnoreMultiTenancy] flag on the Entity level. I saw that there is a check here:
however i tried adding [IgnoreMultiTenancy] to the Entity but it doens't seem to work e.g. 
Is there something I am missing? Thanks
20 Answer(s)
-
0
Hello ,
Please check this https://github.com/abpframework/abp/issues/9828
Thank you.
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi Anjali,
It seems like the OP was asking about ignoring the [IgnoreMultiTenancy] decorator. My question is different, as I want to apply this [IgnoreMultiTenancy] decorator on an entity level.
Otherwise, we may need to create a new DbContext for all entities which are IMultiTenant but still use Host DB Context (Even if the Tenant has its own DB Connection String)
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hello,
oh is that the case, sorry it's my bad. I will check again and get back to you asap.
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Thank you. The workaround I will then try is to implement a new DbContext class and apply the
[IgnoreMultiTenancy]attributeI've Created a class called
HostOnlyDbContext.cs[ConnectionStringName("Default")] [IgnoreMultiTenancy] public class HostOnlyDbContext : AbpSolution4DbContextBase<HostOnlyDbContext> { public DbSet<Experience> Experiences { get; set; } = null!; public HostOnlyDbContext(DbContextOptions<HostOnlyDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder builder) { builder.SetMultiTenancySide(MultiTenancySides.Both); builder.Entity<Experience>(b => { b.ToTable(AbpSolution4Consts.DbTablePrefix + "Experiences", AbpSolution4Consts.DbSchema); b.ConfigureByConvention(); b.Property(x => x.TenantId).HasColumnName(nameof(Experience.TenantId)); b.Property(x => x.Name).HasColumnName(nameof(Experience.Name)); }); }And also registered the DbContext in
AbpSolution4EntityFrameworkCoreModule.cspublic override void ConfigureServices(ServiceConfigurationContext context) { context.Services.AddAbpDbContext<AbpSolution4DbContext>(options => { /* Remove "includeAllEntities: true" to create * default repositories only for aggregate roots */ options.AddDefaultRepositories(includeAllEntities: true); options.AddRepository<Conversation, Conversations.EfCoreConversationRepository>(); }); context.Services.AddAbpDbContext<HostOnlyDbContext>(options => { options.AddDefaultRepositories(includeAllEntities: true); options.AddRepository<Experience, Experiences.EfCoreExperienceRepository>(); });Would this work? I am having trouble understanding how the original
AbpSolution4DbContextis being injected and whether it is possible to referenceAbpSolution4DbContextfor theConversationentity but useHostOnlyDbContextfor theExperienceentity.also, is there a way to migrate BOTH the
AbpSolution4DbContextandHostOnlyDbContextduring DB Migration? Currently it is only running migrations forAbpSolution4DbContextMarkdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi Maliming,
Just as context, our business requirement is that for some custom entities (e.g. AppBooks), that our data must reside only in the Host Database (even if tenant is using its own DB Connection String). But the data must still be accessible from the Tenant.
Is there a better way to achieve this outcome in the ABP framework?
Thank you
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi Maliming,
Noted on that. As I still need some filtering by
TenantId, A possible workaround for me is to addTenantIdwithout implementingIMultiTenant.Is there any way to automatically populate this
TenantIdfield with theCurrentTenant? Thank youMarkdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Noted on that. As I still need some filtering by TenantId, A possible workaround for me is to add TenantId without implementing IMultiTenant.
You can override the ef core filter method. https://abp.io/docs/latest/framework/infrastructure/data-filtering?_redirected=B8ABF606AA1BDF5C629883DF1061649A#entityframework-core
Is there any way to automatically populate this TenantId field with the CurrentTenant?
The entity's
TenantIdhas nothing to do withICurrentTenantICurrentTenantvalue coming from claims.Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi Maliming,
Refering to documentation snippet below. As I would like to auto-populate my
TenantIdCustomproperty (**not ** inherited from IMultiTenant), is there a way to implement the auto-population logic similar to how ABP framework auto populates TenantId?Will post a code implementation shortly
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Something like this? (I not sure if
ICurrentTenantis available for dependency injection on a Entity level though)Injecting into
DomainServiceshould work right? But this is not desirable, as I would need to override the CreateAsync method for every DomainService for the entity. I would prefer if the Entity itself does the initialization, similar to classes implementingIMultiTenant
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
hi
The
tenantidset in the base class.You can call the
YouEntityHelper.TrySetTenantId(this);This breaks the framework design and may cause uncertainty in related functions.
public abstract class Entity : IEntity { protected Entity() { EntityHelper.TrySetTenantId(this); } } public static class YourEntityHelper { public static void TrySetTenantId(IEntity entity) { //if (entity is not IMultiTenant multiTenantEntity) //{ // return; //} //make sure entity is contains `TenantIdCustom` var tenantId = AsyncLocalCurrentTenantAccessor.Instance.Current?.TenantId; if (tenantId == multiTenantEntity.TenantIdCustom) { return; } ObjectHelper.TrySetProperty( multiTenantEntity, x => x.TenantIdCustom, () => tenantId ); } }Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Thank you for the insights. As I do not want to deviate from the framework design, I will implement the manual assignment of
TenantIdCustomupon entity creation (We forsee only a limited number of such entities)In addition, I've implemented a DataFilter within
MyApplcaitionDbContext.csprotected bool IsMultiTenantInHostDb => DataFilter?.IsEnabled<IMultiTenantInHostDb>() ?? false; protected override bool ShouldFilterEntity<TEntity>(IMutableEntityType entityType) { if (typeof(IMultiTenantInHostDb).IsAssignableFrom(typeof(TEntity))) { return true; // Apply filter for entities implementing IMultiTenantInHostDb } return base.ShouldFilterEntity<TEntity>(entityType); } protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>(ModelBuilder modelBuilder) { var expression = base.CreateFilterExpression<TEntity>(modelBuilder); if (typeof(IMultiTenantInHostDb).IsAssignableFrom(typeof(TEntity))) { // Get the current tenant ID var currentTenantId = CurrentTenant.Id; Console.WriteLine("currentTenantId:"); Console.WriteLine(currentTenantId); // Create the filter expression Expression<Func<TEntity, bool>> tenantFilter = e => !IsMultiTenantInHostDb || (EF.Property<Guid?>(e, "TenantIdCustom") == currentTenantId || EF.Property<Guid?>(e, "TenantIdCustom") == null); expression = expression == null ? tenantFilter : QueryFilterExpressionHelper.CombineExpressions(expression, tenantFilter); } return expression; }as per your reference for ef core filter: https://abp.io/docs/latest/framework/infrastructure/data-filtering?_redirected=B8ABF606AA1BDF5C629883DF1061649A#entityframework-core
However the
currentTenantIdcoming as null, even when logged in as a tenant. Is there some issue with my usage of CurrentTenant.Id?Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Posted this article on the topic: https://medium.com/@kaffeeebene/abp-in-depth-storing-key-tenant-data-in-the-host-database-while-keeping-the-rest-in-tenant-ca2aca0e4cd2
Thanks!
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)




