背景
在使用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();
}
}
}