实现原理

当我们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. 「Python实用秘技09」更好用的函数运算缓存

    本文完整示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/PythonPracticalSkills 这是我的系列文章「Python实用秘技」的第9期 ...

  2. prim最小生成树算法(堆优化)

    prim算法原理和dijkstra算法差不多,依然不能处理负边 1 #include<bits/stdc++.h> 2 using namespace std; 3 struct edge ...

  3. @Convert 注解在jpa中进行查询的注意事项

    如果要实现实体类中属性的类型和数据库表中字段的类型相互转化,则需要使用 @Convert 注解 package javax.persistence; import java.lang.annotati ...

  4. HTML表单学习

    HTML表单学习 前言 HTML基础学习会由HTML基础标签学习.HTML表单学习和一张思维导图总结HTML基础三篇文章构成,文章中博主会提取出重点常用的知识和经常出现的bug,提高学习的效率,后续会 ...

  5. 小试牛刀:Linux中部署RabbitMQ

    一.下载地址 本人采用的是 RabbitMQ 3.8.20+ Erlang 23.3.4.16 1.Erlang下载:https://github.com/erlang/otp/releases 2. ...

  6. ora-26002:Informatica的Powercenter跑ETL时,出现ora-26002错误解决办法

    在使用Informatica进行ETL导数的时候,出现下面的错误: WRT_8229 Database errors occurred: ORA-26002: Table REPORT.TB_JK_0 ...

  7. 配置 Druid 数据源及密码加密-SpringBoot 2.7 实战基础

    在SpringBoot中配置 Druid 数据源及密码加密的方法 前文集成 MyBatis Plus,实现了一组增删改查接口.在启动服务时,从控制台中可以看出 Spring Boot 默认使用 Hik ...

  8. 为MySQL MGR实现简单的负载均衡代理

    GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 原创:万里数据库,花家舍 导读 在多写(多节点写入)数据库(例如MySQL MGR的multi-primary mode) ...

  9. React报错之Functions are not valid as a React child

    正文从这开始~ 总览 产生"Functions are not valid as a React child. This may happen if you return a Compone ...

  10. SpringBoot 注解简介(持续更新)

    虽然工作中交替会使用spring mvc 和spring boot 框架,但实际对spring中的很多注解并不是很了解,本篇将持续更新学习到的spring 注解. Spring 主入口类上的注解 Sp ...