EFCore分表实现
实现原理
当我们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();
}
使用方式
这里只介绍构造函数传参使用方式
DbContextOptionsBuilder<DbContextBase> optionsBuilder = new DbContextOptionsBuilder<DbContextBase>();
optionsBuilder.UseSqlServer("connStr");
var options = optionsBuilder.Options;
using (var dbContext = new DbContextBase("202209", options))
{
//TODO....
}
跨上下文使用事务
这里需要主要的是,跨上下文使用事务必须使用同一个连接,所以optionsBuilder.UseSqlServer(connection);这里的写法改变一下,使用同一连接
DbContextOptionsBuilder<DbContextBase> optionsBuilder = new DbContextOptionsBuilder<DbContextBase>();
IDbConnection connection = new SqlConnection("connStr");
optionsBuilder.UseSqlServer(connection);
var options = optionsBuilder.Options;
using (var dbContext = new DbContextBase("202209", options))
{
using (var transaction =await dbContext.Database.BeginTransactionAsync())
{
using (var dbContext2 = new DbContextBase("202210", options))
{
await dbContext2.Database.UseTransactionAsync(transaction);
//TODO....
transaction.Commit();
}
}
}
总结
EFCore分表的实现大致全是这样,没有什么区别。可以参考一些开源的框架,对现有的系统进行适当的调整,毕竟别人写的并不一定适合你。希望这篇文章可以帮到你。
EFCore分表实现的更多相关文章
- .Net下极限生产力之efcore分表分库全自动化迁移CodeFirst
.Net下极限生产力之分表分库全自动化Migrations Code-First ## 介绍 本文ShardinfCore版本x.6.x.x+ 本期主角: - [`ShardingCore`](htt ...
- efcore分表下"完美"实现
ShardingCore 如何呈现"完美"分表 这篇文章是我针对efcore的分表的简单介绍,如果您有以下需求那么可以自己选择是否使用本框架,本框架将一直持续更新下去,并且免费开源 ...
- efcore分表分库原理解析
ShardingCore ShardingCore 易用.简单.高性能.普适性,是一款扩展针对efcore生态下的分表分库的扩展解决方案,支持efcore2+的所有版本,支持efcore2+的所有数据 ...
- EFCore.Sharding(EFCore开源分表框架)
EFCore.Sharding(EFCore开源分表框架) 简介 引言 开始 准备 配置 使用 按时间自动分表 性能测试 其它简单操作(非Sharing) 总结 简介 本框架旨在为EF Core提供S ...
- 基于efcore的分表组件开源
ShardingCore ShardingCore 是一个支持efcore 2.x 3.x 5.x的一个对于数据库分表的一个简易扩展, 目前该库暂未支持分库(未来会支持),仅支持分表,该项目的理念是让 ...
- EasySharding.EFCore 如何设计使用一套代码完成的EFCore Migration 构建Saas系统多租户不同业务需求且满足租户自定义分库分表、数据迁移能力?
下面用一篇文章来完成这些事情 多租户系统的设计单纯的来说业务,一套Saas多租户的系统,面临很多业务复杂性,不同的租户存在不同的业务需求,大部分相同的表结构,那么如何使用EFCore来完成这样的设计呢 ...
- efcore使用ShardingCore实现分表分库下的多租户
efcore使用ShardingCore实现分表分库下的多租户 介绍 本期主角:ShardingCore 一款ef-core下高性能.轻量级针对分表分库读写分离的解决方案,具有零依赖.零学习成本.零业 ...
- efcore在Saas系统下多租户零脚本分表分库读写分离解决方案
efcore在Saas系统下多租户零脚本分表分库读写分离解决方案 ## 介绍 本文ShardinfCore版本x.6.0.20+ 本期主角: - [`ShardingCore`](https://gi ...
- EF多租户实例:快速实现分库分表
前言 来到这篇随笔,我们继续演示如何实现EF多租户. 今天主要是演示多租户下的变形,为下图所示 实施 项目结构 这次我们的示例项目进行了精简,仅有一个API项目,直接包含所有代码. 其中Control ...
随机推荐
- Python图像处理丨三种实现图像形态学转化运算模式
摘要:本篇文章主要讲解Python调用OpenCV实现图像形态学转化,包括图像开运算.图像闭运算和梯度运算 本文分享自华为云社区<[Python图像处理] 九.形态学之图像开运算.闭运算.梯度运 ...
- net core 3.1使用identityServer登录时signin-oidc报Correlation failed的解决方法
此问题全网找了很久,也困扰了我很久,始终没有找到解决方法.今天结合网上其他问题的帖子,自己研究的半天,终于找到了这个解决方法,经亲自测试可行.欢迎大牛指导指正. 有时客户收藏的系统地址是认证端的,然后 ...
- jsx/tsx使用cssModule和typescript-plugin-css-modules
目录 1,前言 2,效果图 3,如何使用 3.1,安装 3.2,配置 4,示例 5,插件错误处理 5.1,错误触发原因 5.2,解决办法 1,前言 在vite/webpack搭建的项目中,不管是vue ...
- 搭建一个完整的K8S集群-------基于CentOS 8系统
创建三个centos节点: 192.168.5.141 k8s-master 192.168.5.142 k8s-nnode1 192.168.5.143 k8s-nnode2 查看centos系统版 ...
- 20220722-Java中this关键字
this关键字知识总结 学习资源:B站韩顺平老师Java入门教学 代码示例1 public class This01 { public static void main(String[] args) ...
- 魔怔愉悦之 Vizing 定理
Vizing 定理 定义 \(\Delta(G)\) 表示图 \(G\) 的点的最大度数,即 \(\displaystyle\Delta G=\max_{i=1}^{|V|}\deg(i)\) . 边 ...
- Linux 用户管理相关命令
1 sudo adduser username # 添加用户 2 sudo adduser --system username # 添加系统用户 3 sudo deluser username # 删 ...
- Odoo4 tree视图左上角新增Button
# 一.直接在tree根元素中新增.这种有个限制就是必须要勾选一或多条记录的时候按钮才会显示 <tree> <header> <button type="obj ...
- Ubuntu 20.04安装Docker
Docker学习系列文章 入门必备:十本你不容错过的Docker入门到精通书籍推荐 day1.全面的Docker快速入门教程 day2.CentOS 8.4安装Docker day3.Windows1 ...
- 业务可视化-让你的流程图"Run"起来(6.定时任务&Spring-Batch的集成)
前言 首先,感谢大家对上一篇文章[业务可视化-让你的流程图"Run"起来(5.SpringBoot集成&微服务编排)]的支持. 分享一下近期我对这个项目的一些改进. 在项目 ...