实现原理

当我们new一个上下文DbContext 后, 每次执行CURD方式时 ,都会依次调用OnConfiguring(),OnModelCreating()两个方法。

  • OnConfiguring() 我们将用来替换一些服务实现,以支持分表的工作
  • OnModelCreating() 我们将用来重新实现 实体与数据库表 的映射关系

每次调用OnModelCreating()时,会判断实体与数据库表的映射关系有没有改变,如果改变则采用新的映射关系。

判断是否发生改变,通过替换 IModelCacheKeyFactory 接口的实现来完成。详情可见:在具有相同 DbContext 类型的多个模型之间进行交替

IModelCacheKeyFactory 实现

DbContextBase 是一个DbContext的实现,,ShardingRuleDbContextBase的一个共有属性。

根据分表规则的不同,每次的映射关系也会不同。

 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() 时,方法内部会调用实现IModelCustomizerModelCustomizer.csCustomize()方法,我们可以将映射关系写在此方法内。

通过继承实现:

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分表实现的更多相关文章

  1. .Net下极限生产力之efcore分表分库全自动化迁移CodeFirst

    .Net下极限生产力之分表分库全自动化Migrations Code-First ## 介绍 本文ShardinfCore版本x.6.x.x+ 本期主角: - [`ShardingCore`](htt ...

  2. efcore分表下"完美"实现

    ShardingCore 如何呈现"完美"分表 这篇文章是我针对efcore的分表的简单介绍,如果您有以下需求那么可以自己选择是否使用本框架,本框架将一直持续更新下去,并且免费开源 ...

  3. efcore分表分库原理解析

    ShardingCore ShardingCore 易用.简单.高性能.普适性,是一款扩展针对efcore生态下的分表分库的扩展解决方案,支持efcore2+的所有版本,支持efcore2+的所有数据 ...

  4. EFCore.Sharding(EFCore开源分表框架)

    EFCore.Sharding(EFCore开源分表框架) 简介 引言 开始 准备 配置 使用 按时间自动分表 性能测试 其它简单操作(非Sharing) 总结 简介 本框架旨在为EF Core提供S ...

  5. 基于efcore的分表组件开源

    ShardingCore ShardingCore 是一个支持efcore 2.x 3.x 5.x的一个对于数据库分表的一个简易扩展, 目前该库暂未支持分库(未来会支持),仅支持分表,该项目的理念是让 ...

  6. EasySharding.EFCore 如何设计使用一套代码完成的EFCore Migration 构建Saas系统多租户不同业务需求且满足租户自定义分库分表、数据迁移能力?

    下面用一篇文章来完成这些事情 多租户系统的设计单纯的来说业务,一套Saas多租户的系统,面临很多业务复杂性,不同的租户存在不同的业务需求,大部分相同的表结构,那么如何使用EFCore来完成这样的设计呢 ...

  7. efcore使用ShardingCore实现分表分库下的多租户

    efcore使用ShardingCore实现分表分库下的多租户 介绍 本期主角:ShardingCore 一款ef-core下高性能.轻量级针对分表分库读写分离的解决方案,具有零依赖.零学习成本.零业 ...

  8. efcore在Saas系统下多租户零脚本分表分库读写分离解决方案

    efcore在Saas系统下多租户零脚本分表分库读写分离解决方案 ## 介绍 本文ShardinfCore版本x.6.0.20+ 本期主角: - [`ShardingCore`](https://gi ...

  9. EF多租户实例:快速实现分库分表

    前言 来到这篇随笔,我们继续演示如何实现EF多租户. 今天主要是演示多租户下的变形,为下图所示 实施 项目结构 这次我们的示例项目进行了精简,仅有一个API项目,直接包含所有代码. 其中Control ...

随机推荐

  1. 虚拟机win7系统安装

    win7 x64虚拟机安装步骤 1.点击创建新虚拟机,选择典型 2.选择客户机操作系统:windows 7 x64 3.命名虚拟机 4.指定磁盘容量 5.点击完成 6.编辑此虚拟机设置 7.内存设置 ...

  2. VGA显示原理

    VGA显示是图像处理的基础,是一开始广泛使用的显示器,大部分机器采用VGA接口驱动,所以后来的显示器需要用VGA-xxx转接口来匹配. 用FPGA来驱动VGA,并不适用于显示动态(如手机显示,GUI) ...

  3. FnOnce,FnMut和Fn

    继承结构 FnOnce FnMut: FnOnce Fn: FnMut FnOnce就是说会转移闭包捕获变量的所有权,在闭包前加上move关键字可以限定此闭包为FnOnce move关键字是强制让环境 ...

  4. 1269: 求最长上升子序列(LIS)

     题目描述: LIS问题(longest increasing subsequence),即:最长上升子序列问题,是动态规划中一个比较经典的问题.具体描述为:一个有n个整数的序列:A[1],A[2], ...

  5. boot issue

    Q:生产过程中不小心把 boot文件删除了 ,或者升级kenerl时发现版本不兼容,需要回退,此时没有快照备份情况如何操作? A:boot 主要文件是内核和grub引导文件   修复方法: 1.进入救 ...

  6. 技术分享 | MySQL Group Replication集群对IP地址的限制导致的一些问题与解决办法

    GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 1. 遇到问题 测试人员小玲准备在docker环境中部署MGR集群进行一些测试,她有三个容器,容器IP分别是: 172.3 ...

  7. Reactive UI -- 反应式编程UI框架入门学习(一)

    推荐一个反应式编程的MVVM跨平台框架. 反应式编程 反应式编程是一种相对于命令式的编程范式,由函数式的组合声明来构建异步数据流.要理解这个概念,可以简单的借助Excel中的单元格函数. 上图中,A1 ...

  8. RocketMQ 详解系列

    什么是RocketMQ RocketMQ作为一款纯java.分布式.队列模型的开源消息中间件,支持事务消息.顺序消息.批量消息.定时消息.消息回溯等.主要功能是异步解耦和流量削峰:. 常见的MQ主要有 ...

  9. ahooks 中那些控制“时机”的hook都是怎么实现的?

    本文是深入浅出 ahooks 源码系列文章的第五篇,该系列已整理成文档-地址.觉得还不错,给个 star 支持一下哈,Thanks. 本文来探索一下 ahooks 是怎么封装 React 的一些执行& ...

  10. HCIA-Datacom 4.1 实验一:访问控制列表配置实验

    实验介绍 访问控制列表ACL(Access Control List)是由一条或多条规则组成的集合.所谓规则,是指描述报文匹配条件的判断语句,这些条件可以是报文的源地址.目的地址.端口号等.ACL本质 ...