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 ...
随机推荐
- 「一本通 1.1 例 4」加工生产调度(贪心算法)(luogu P1248)题解
加工生产调度 题目描述 某工厂收到了 n n n 个产品的订单,这 n n n 个产品分别在 A.B 两个车间加工,并且必须先在 A 车间加工后才可以到 B 车间加工. 某个产品 i i i 在 A. ...
- Python 封装SNMP调用接口
PySNMP 是一个纯粹用Python实现的SNMP,用PySNMP的最抽象的API为One-line Applications,其中有两类API:同步的和非同步的,都在模块pysnmp.entity ...
- PDF 拆分/合并
不会真的有人会去下载那些广告免费,实则要收会员费的黑心软件来进行PDF的拆分合并吧??? 在下载两个均不能免费实现PDF自由拆分.合并,以及PDF打印方式会增加文件大小的情况下,一个合格的程序员肯定不 ...
- 关于hive分区,你知道多少呢?
文末查看关键字,回复赠书 一.理论基础 1.Hive分区背景 在Hive Select查询中一般会扫描整个表内容,会消耗很多时间做没必要的工作.有时候只需要扫描表中关心的一部分数据,因此建表时引入 ...
- WPF主窗体调用 User32的SetWindowPos 设置窗体置顶会导致与其他窗体抢夺焦点的问题
最近发现:自己开发的窗体应用,在二级弹窗或者提示框弹出的时候,交替点击窗体和窗体外(相当于窗体交替的获取焦点和失去焦点),都会导致其他的应用一闪一闪的. 经过排查,是由于该窗体由于部分因素考虑,用了 ...
- 如何实现 System.out.println("a") 显示 b
今天看到一篇文章不用反射,能否交换两个字符串的值. 心想字符串常量在常量池里面,是在就算用了反射也交换不了吧.转念一想,不对,字符串常量虽然本身在常量池里面,但是它依然是个对象,那么 private ...
- Excel 名称管理器是什么,并实现一个级联选择框
名称 在 Excel 中,每一个单元格都有自己的名称.表格横向是字母,纵向是数字,组合起来就是一个单元格的名称. A13 所代表的是 A 列,13 行的单元格.把一组单元格组合起来,加上一个名称,在 ...
- Windows 注册表是什么?它的作用是什么?
学习目的 了解 Windows 注册表的概念 了解 Windows 注册表的作用 注册表的概念 历史发展 在 Windows 3.x 操作系统中,注册表是一个极小文件,其文件名为 Reg.dat,里面 ...
- Java精进-20分钟学会mybatis使用
文字分享 希望现在的你无论有明确具体的目标还是没有,都能重视自己的需求和目标,并且常常回顾,或许可以找一个你习惯的方式写出来,挂在哪里,电脑或日记本都好.当你疲惫或迷茫的时候拿出来看一下,这在情怀领域 ...
- 【JDBC】学习路径10-c3p0数据源的使用(JDBC完结)
第一章:下载 c3p0官网:https://www.mchange.com/projects/c3p0/ 这个是SourceForge提供的下载地址:https://sourceforge.net/p ...