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

 

posted @ 2020-04-04 15:25  woailibian  阅读(3436)  评论(3编辑  收藏  举报