前言
来到这篇随笔, 我们继续演示如何实现 EF 多租户.
今天主要是演示多租户下的变形, 为下图所示
实施
项目结构
这次我们的示例项目进行了精简, 仅有一个 API 项目, 直接包含所有代码.
其中 Controller,StoreContext,Entity 都完全和以往的示例一模一样, 这里就不再过多介绍了.
具有主要区别的是 CombinedConnectionGenerator 和 Startup
代码解释
1. 首先要关注的是作为入口的 Startup , 还是一个套路, 分别在 ConfigureService 注册 EF 多租户, 在 Configure 配置中间件.
ConfigureService 还是一贯的简单. 但是注意这里使用的 AddMySqlPerTable 这个模式.
在混合的模式中, 需要已最小的单元作为服务注册. 由于这次是数据库和数据表混合模式, 所以需要用数据表来注册.
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddScoped<IConnectionGenerator, CombindedConnectionGenerator>();
- services.AddMySqlPerTable<StoreDbContext>(settings =>
- {
- settings.ConnectionPrefix = "mysql_";
- });
- services.AddControllers();
- }
Configure 的使用更加简单, 只需要添加中间件 TenantInfoMiddleware 即可.
- public void Configure(IApplicationBuilder App, IwebHostEnvironment env)
- {
- if (env.IsDevelopment())
- {
- App.UseDeveloperExceptionPage();
- }
- App.UseMiddleware<TenantInfoMiddleware>();
- App.UseRouting();
- App.UseEndpoints(endpoints =>
- {
- endpoints.MapControllers();
- });
- }
2. 这次需要自己实现 ConnectionGenerator
关键点有 2 个,
第一个关键点, 由于我们的类库是同时支持多个 DbContext 的, 所以需要有 TenantKey 去区分. 由于有种特殊情况, 需要一个 ConnectionGenerator 同时支持多个 DbContext , 所以这里提供了 MatchTenantKey 方法作为补充的判断依据.
可以看出来, 我们这里 TenantKey 为空, 所以一般都不会匹配中. 示例中完全是依靠 MatchTenantKey 来做匹配的.
第二个关键点, GetConnection 作为最主要的逻辑方法, 通过对 TenantName 的数字部分进行取模, 最终拼接处 ConnectionString 的键值
并且通过 Configuration 获取连接字符串
- public class CombindedConnectionGenerator : IConnectionGenerator
- {
- private readonly IConfiguration configuration;
- public string TenantKey => "";
- public CombindedConnectionGenerator(IConfiguration configuration)
- {
- this.configuration = configuration;
- }
- public string GetConnection(TenantOption option, TenantInfo tenantInfo)
- {
- var span = tenantInfo.Name.AsSpan();
- if (span.Length> 4 && int.TryParse(span[5].ToString(), out var number))
- {
- return configuration.GetConnectionString($"{option.ConnectionPrefix}container{number % 2 + 1}");
- }
- throw new NotSupportedException("tenant invalid");
- }
- public bool MatchTenantKey(string tenantKey)
- {
- return true;
- }
- }
检验结果
检验结果我觉得已经没有必要的, 都是同样的套路, 主要的区别是, 之前的只有一个数据库, 或者多个数据库
这次的混合模式, 主要是一个数据库作为一个 container, 里面可以同时包含多个 product 数据表.
Container1
Container2
总结
其实这个例子也是非常简单的, 目的是让每个人都能快速应用复杂的分库分表
下一篇文章将会通过多租户实现读写分离.
关于这个文章的所有代码, 已经同步到 GitHub
来源: https://www.cnblogs.com/woailibian/p/12632019.html