在使用ABP vNext过程中,因为我们的用户体系庞大,所以一直与其他业务同时开发,在开发其他业务模块时,我们一直存在着误区:认为ABP vNext 自动处理了数据新增时的租户Id(TenantId)的自动赋值插入。直到我们开始接入用户权限模块后,发现并不如此。
思路为了实现字段的自动赋值,且无感知的,我们的思路是做类似拦截器,在上层应用新增数据相关代码流程进入DbContext的时候,在DbContext中进行处理。
其他 问题为了实现上层业务开发人员的【无感知】,哪怕在代码编写过程中,我们也不希望开发人员有所明显感知自己在使用经过处理的DbContext,于是想到了与Volo.Abp.EntityFrameworkCore.AbpDbContext使用同一个名字AbpDbContext。
解决方案我们首先知道,在C#中,如果有两个命名空间下,具有同名类,那么两个类的优先级为何。
假设,我们写的类在:TripleH.AbpDbContext。我们在使用这个类的地方的命名空间为:TripleH.*.AClass。
那么在AClass中使用AbpDbContext时,我们就算引用了Volo.Abp.EntityFrameworkCore命名空间,编译时也会使用TripleH.AbpDbContext。
这是因为,C#在此处的优先级决定的,它优先找Triple.*命名空间下的AbpDbContext这个类,如果没有,就会逐级往上,找Triple命名空间下的AbpDbContext,如果找到了,就会直接使用它,使用时连命名空间都不需要手动引用。当然,如果没找过,才会去其他命名空间如Volo.Abp.EntityFrameworkCore中寻找。
实现 namespace TripleH { public abstract class AbpDbContext<TDbContext> : Volo.Abp.EntityFrameworkCore.AbpDbContext<TDbContext> where TDbContext : AbpDbContext<TDbContext> { public AbpDbContext(DbContextOptions<TDbContext> options) : base(options) { } protected override void ApplyAbpConceptsForAddedEntity(EntityEntry entry, EntityChangeReport changeReport) { SetTenantIdIfNull(entry); base.ApplyAbpConceptsForAddedEntity(entry, changeReport); } protected virtual void SetTenantIdIfNull(EntityEntry entry) { if (entry.Entity is IMultiTenant entityWithTenantId && entityWithTenantId.TenantId == null && IsMultiTenantFilterEnabled) { ObjectHelper.TrySetProperty(entityWithTenantId, e => e.TenantId, () => CurrentTenant.Id); } } } } 使用 //无需额外引用TripleH命名空间,做到真正的无感知,当然鼠标放到AbpDbContext上,VS 会告诉你是哪个命名空间 namespace TripleH.Test.EntityFrameworkCore { //此处继承的AbpDbContext,便是来自TripleH命名空间下,而非Abp [ConnectionStringName(BasicDbProperties.ConnectionStringName)] public class BasicDbContext : AbpDbContext<BasicDbContext>, IBasicDbContext { public BasicDbContext(DbContextOptions<BasicDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); builder.ConfigureBasic(); } } }