实现原理当我们new
一个上下文DbContext
后, 每次执行CURD方式时 ,都会依次调用OnConfiguring()
,OnModelCreating()
两个方法 。
OnConfiguring()
我们将用来替换一些服务实现,以支持分表的工作OnModelCreating()
我们将用来重新实现 实体与数据库表 的映射关系
OnModelCreating()
时,会判断实体与数据库表的映射关系有没有改变,如果改变则采用新的映射关系 。判断是否发生改变,通过替换
IModelCacheKeyFactory
接口的实现来完成 。详情可见:在具有相同 DbContext 类型的多个模型之间进行交替IModelCacheKeyFactory
实现DbContextBase
是一个DbContext
的实现,,ShardingRule
是DbContextBase
的一个共有属性 。根据分表规则的不同,每次的映射关系也会不同 。 public class DynamicModelCacheKeyFactoryDesignTimeSupport : IModelCacheKeyFactory {public object Create(DbContext context, bool designTime)=> context is DbContextBase dynamicContext? (context.GetType(), dynamicContext.ShardingRule, designTime): (object)context.GetType();public object Create(DbContext context)=> Create(context, false); }
OnConfiguring()
替换接口实现 protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {base.OnConfiguring(optionsBuilder);//如果分页规则有 ,代表需要分页 , 那么需要替换对应的服务实现if (!string.IsNullOrEmpty(this.ShardingRule)){optionsBuilder.ReplaceService<IModelCacheKeyFactory, DynamicModelCacheKeyFactoryDesignTimeSupport>();} }
ModelCustomizer
实现在每次调用 OnModelCreating()
时 , 方法内部会调用实现IModelCustomizer
的 ModelCustomizer.cs
的Customize()
方法,我们可以将映射关系写在此方法内 。通过继承实现:
IShardingTypeFinder
是一个类型查找器,请自行实现 。public class ShardingModelCustomizer : ModelCustomizer{public ShardingModelCustomizer(ModelCustomizerDependencies dependencies) : base(dependencies){}public override void Customize(ModelBuilder modelBuilder, DbContext context){base.Customize(modelBuilder, context);var dbContextBase = context as DbContextBase;var shardingTypeFinder = dbContextBase.ServiceProvider.GetService<IShardingTypeFinder>();//查找需要重新映射表名的类var shardingTypes = shardingTypeFinder.FindAll(true);if (shardingTypes != null && shardingTypes.Count() > 0){if (context is DbContextBase contextBase){if (!string.IsNullOrEmpty(contextBase.ShardingRule)){foreach (var type in shardingTypes){switch (contextBase.DbContextOptions.DatabaseType){case DatabaseType.SqlServer:modelBuilder.Entity(type).ToTable($"{type.Name}_{contextBase.ShardingRule}");break;case DatabaseType.Sqlite:modelBuilder.Entity(type).ToTable($"{type.Name}_{contextBase.ShardingRule}");break;case DatabaseType.MySql:modelBuilder.Entity(type).ToTable($"{type.Name}_{contextBase.ShardingRule}".ToMySQLName());break;case DatabaseType.Oracle:modelBuilder.Entity(type).ToTable($"{type.Name}_{contextBase.ShardingRule}".ToOracleName());break;default:modelBuilder.Entity(type).ToTable($"{type.Name}_{contextBase.ShardingRule}");break;}}}}}}}
OnConfiguring()
替换接口实现protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder){base.OnConfiguring(optionsBuilder);//如果分页规则有,代表需要分页, 那么需要替换对应的服务实现if (!string.IsNullOrEmpty(this.ShardingRule)){optionsBuilder.ReplaceService<IModelCacheKeyFactory, DynamicModelCacheKeyFactoryDesignTimeSupport>().ReplaceService<IModelCustomizer, ShardingModelCustomizer>();}}
DbContextBase
构造函数修改上文提到了ShardingRule
这个属性的出现,如何给这个属性赋值呢?有两种方式:- 构造函数传参
- 通过接口获取
public string ShardingRule { get; set; } public DbContextBase(string shardingRule, DbContextOptions options) : base(options) {ShardingRule = shardingRule; }
通过接口获取IShardingRule
是实现规则名称的自定义接口,自行实现 protected DbContextBase(DbContextOptions options, IServiceProvider serviceProvider): base(options) {ShardingRule = (serviceProvider.GetService<IShardingRule>()).GetValue(); }
使用方式【EFCore分表实现】这里只介绍构造函数传参使用方式 DbContextOptionsBuilder<DbContextBase> optionsBuilder = new DbContextOptionsBuilder<DbContextBase>(); optionsBuilder.UseSqlServer("connStr"); var options =optionsBuilder.Options; using (var dbContext = new DbContextBase("202209", options)) {//TODO.... }
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 利用msg_msg实现任意地址读写
- 用AR Engine手部骨骼跟踪能力实现虚拟手表试戴
- 含源码 手把手教你使用LabVIEW人工智能视觉工具包快速实现传统Opencv算子的调用
- Jmix 中 REST API 的两种实现
- 含源码 手把手教你使用LabVIEW人工智能视觉工具包快速实现图像读取与采集
- 之三 2流高手速成记:SpringBoot整合mybatis/mybatis-plus实现数据持久化
- 一百一十九 salesforce零基础学习In-App Guidance实现引导页操作功能
- 五 JPA - 原生SQL实现增删改查
- Vue实现拖拽穿梭框功能四种方式
- Python实现给图片加水印功能