[英]Convert EF-based app to multi-tenant by way of context overrides
我有一個實體框架,我必須制作多租戶的基於代碼的應用程序,也就是說,現在大約有六個“頂級”實體需要引用特定的租戶 ID。 (當我們擁有 100 名用戶時,不,我們不會維護單個架構,因此請不要建議這樣做。:))
通過像 EF 這樣的面向對象的數據訪問抽象,我試圖想象如何到達不需要更改 dbcontext 之外的任何底層代碼即可完成這項工作的地方。 本質上,我想用這些作為我的成功標准:
似乎可以使用實體類本身來設置租戶 ID(還沒有考慮過注入,某種墊片卡在那里),但我不確定如何最好地添加額外的過濾器用於查詢。
我不確定它可以在沒有代碼更改的情況下完全完成,但這是我將如何處理這個問題。 首先,為您的多租戶實體引入一個接口(我假設每個實體都有TenantID
屬性,映射到數據庫列):
public interface IMultiTenantEntity {
int TenantID { get; set; }
}
然后為您的所有實體實施它。 它們是自動生成的,但是是部分的,所以只需執行以下操作:
public partial class YourEntity : IMultiTenantEntity {}
現在,要在保存時填充此屬性,請在您的上下文中覆蓋SaveChanges
(同樣,它是自動生成的,但是是部分的,因此您不必觸摸自動生成的代碼):
public partial class YourContext : DbContext
{
private int _tenantId;
public override int SaveChanges() {
var addedEntities = this.ChangeTracker.Entries().Where(c => c.State == EntityState.Added)
.Select(c => c.Entity).OfType<IMultiTenantEntity>();
foreach (var entity in addedEntities) {
entity.TenantID = _tenantId;
}
return base.SaveChanges();
}
public IQueryable<Code> TenantCodes => this.Codes.Where(c => c.TenantID == _tenantId);
}
上面我假設您已經以某種方式將當前租戶 ID 注入_tenantId
字段。
然后,對於每個實體集,添加單獨的屬性,該屬性將返回由TenantID
過濾的此集(再次在您的上下文的部分類中):
public IQueryable<YourEntity> TenantYourEntities => this.YourEntities.Where(c => c.TenantID == _tenantId);
現在您需要做的就是找到對YourEntities
集的所有引用(右鍵單擊 > 查找所有引用)並將它們替換為對TenantYourEntities
引用。 然后您的所有查詢都將被TenantID
過濾,無需太多工作。 當然,不要替換使用 DbSet 修改實體的引用( Db.YourEntities.Add(...)
)。
好吧,從技術上講,只要在上下文實例化時知道租戶 ID,您就可以簡單地在上下文中設置一個具有該值的字段,並在重載中引用該字段。 例如,您可以執行一些操作,例如從應用程序設置中讀取它。 右鍵單擊您的項目並選擇“屬性”。 然后,轉到“設置”選項卡,將其打開。 放入您將在開發中使用的任何內容。 然后,為每個租戶為您的項目添加配置,並編輯配置轉換以將其切換為適當的值。 然后,在您的 DI 初始化中,您可以讀取此設置值並將其作為常量注入。
如果租戶是在運行時設置的,例如通過 URL 的一部分,那么使用 DI 會變得有點困難。 上下文通常是請求范圍的,所以這不是一個真正的問題。 但是,DI 初始化通常不在請求管道內完成。 在這一點上,你可能只需要手動設置的值,或以其他方式創建內代碼的背景下,為請求管道,如控制器的一部分。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.