EF多租戶實例:快速實現分庫分表

前言

來到這篇隨筆,我們繼續演示如何實現EF多租戶。

今天主要是演示多租戶下的變形,為下圖所示

 

 

實施

項目結構

這次我們的示例項目進行了精簡,僅有一個API項目,直接包含所有代碼。

其中Controller,StoreContext,Entity都完全和以往的示例一模一樣,這裡就不再過多介紹了。

具有主要區別的是 CombinedConnectionGenerator 和 Startup 

 

 

代碼解釋

1. 首先要關注的是作為入口的 Startup ,還是一個套路,分別在 ConfigureService 註冊EF多租戶, 在 Configure 配置中間件。

ConfigureService 還是一貫的簡單。但是注意這裡使用的 AddMySqlPerTable 這個模式。

在混合的模式中,需要已最小的單元作為服務註冊。由於這次是數據庫和數據表混合模式,所以需要用數據表來註冊。

1 public void ConfigureServices(IServiceCollection services)  2 {  3     services.AddScoped<IConnectionGenerator, CombindedConnectionGenerator>();  4     services.AddMySqlPerTable<StoreDbContext>(settings =>  5     {  6         settings.ConnectionPrefix = "mysql_";  7     });  8     services.AddControllers();  9 }

Configure的使用更加簡單,只需要添加中間件 TenantInfoMiddleware 即可。

 1 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)   2 {   3     if (env.IsDevelopment())   4     {   5         app.UseDeveloperExceptionPage();   6     }   7   8     app.UseMiddleware<TenantInfoMiddleware>();   9  10     app.UseRouting();  11  12     app.UseEndpoints(endpoints =>  13     {  14         endpoints.MapControllers();  15     });  16 }

 

2. 這次需要自己實現 ConnectionGenerator 

關鍵點有2個,

第一個關鍵點,由於我們的類庫是同時支持多個DbContext的,所以需要有TenantKey去區分。由於有種特殊情況,需要一個 ConnectionGenerator 同時支持多個 DbContext ,所以這裡提供了 MatchTenantKey 方法作為補充的判斷依據。

可以看出來,我們這裡TenantKey 為空,所以一般都不會匹配中。示例中完全是依靠 MatchTenantKey 來做匹配的。

第二個關鍵點,GetConnection 作為最主要的邏輯方法,通過對TenantName 的數字部分進行取模,最終拼接處ConnectionString的鍵值

並且通過 Configuration 獲取連接字符串

 1 public class CombindedConnectionGenerator : IConnectionGenerator   2 {   3     private readonly IConfiguration configuration;   4     public string TenantKey => "";   5   6     public CombindedConnectionGenerator(IConfiguration configuration)   7     {   8         this.configuration = configuration;   9     }  10  11  12     public string GetConnection(TenantOption option, TenantInfo tenantInfo)  13     {  14         var span = tenantInfo.Name.AsSpan();  15         if (span.Length > 4 && int.TryParse(span[5].ToString(), out var number))  16         {  17             return configuration.GetConnectionString($"{option.ConnectionPrefix}container{number % 2 + 1}");  18         }  19         throw new NotSupportedException("tenant invalid");  20     }  21  22     public bool MatchTenantKey(string tenantKey)  23     {  24         return true;  25     }  26 }

 

 

檢驗結果

檢驗結果我覺得已經沒有必要的,都是同樣的套路,主要的區別是,之前的只有一個數據庫,或者多個數據庫

這次的混合模式,主要是一個數據庫作為一個container,裏面可以同時包含多個product數據表。

Container1

 

Container2

 

 

 

總結

其實這個例子也是非常簡單的,目的是讓每個人都能快速應用複雜的分庫分表

下一篇文章將會通過多租戶實現讀寫分離。

 

關於這個文章的所有代碼,已經同步到Github

https://github.com/woailibain/kiwiho.EFcore.MultiTenant/tree/master/example/mix_mode/kiwiho.EFcore.MultiTenant.MixMode