ShardingCore 易用、简单、高性能、普适性,是一款扩展针对efcore生态下的分表分库的扩展解决方案,支持efcore2+的所有版本,支持efcore2+的所有数据库、支持自定义路由、动态路由、高性能分页、读写分离的一款组件,如果你喜欢这组件或者这个组件对你有帮助请点击下发star让更多的.neter可以看到使用


Gitee Star 助力dotnet 生态 Github Star


背景

你是否在使用efcore,你是否在使用abp,你是否对目前的分表十分厌恶,手动指定表让你的代码无辜多出很多胶水代码,那么这次的文章可以很好的帮你解决掉当前的困难点,sharding-core 针对efcore的分库分表读写分离的痛点进行扩展,可以完美集成到efcore生态的系统里面,无论你是abp还是其他使用efcore的框架,你确定真的不看一下吗,如何集成abp当时我发布这个库的时候就有很多人问我是否支持,我的回答是支持的,只是个人没有时间去实现。这次已经实现了我这边将分享下如何集成sharding-coreabp vnext中。

距离上一篇博客已经两周了,在这两周期间本人还是做了很多事情,针对优化sharding-core的使用和体验,就在上周五傍晚的时候有个使用abp的同学联系我,问我什么时候支持abp vnext,其实这个计划我很早之前就在issue里面备注了,只是获取用abp的同学没有怎么关注这个类库也没人提出来,所以就搁置了。因为sharding-core是一款几乎可以说可以集成到任何efcore生态下的所以原则上abp上集成应该是没什么难度的,因为本人使用abp不是很多所以这边自己按官方教程进行了初步的项目搭建,然后又用了一会功夫了解了abp源码(之前有了解过)清楚了dbcontext的创建过程所以很快就继承好了一个todoapp
接下来我将用一篇博客的篇幅来介绍如何将sharing-core集成到abp vnext中。

如何集成

abp项目创建/下载

我这边是通过github进行了例子的todoapp 进行下载,下载后是一个集合例子,我们获取TodoApp项目进行单独处理,打开然后编译。

注意如果你自己会新建那么也是一样的

集成abp思路

用过abp的用户都应该知道abp的dbcontext没有什么不一样,唯一需要注意的就是
  • abp:只要你的dbcontext继承至 public class TDbContext:AbpDbContext<TDbContext>那么就可以完美使用.
    但是sharding-core的使用我们通过readme来查看发现

  • sharidng-core:只要你的dbcontext继承至public class TDbContext:AbstractShardingDbContext那么你就可以完美使用.

好家伙直接给想自己集成的同学搞蒙蔽了,c#又不是c艹没有多继承啊那怎么办,但是这边其实是有一个误区的就是abp确实需要继承abpdbcontext但是sharding-core是已接口作为依赖来开发的,所以我们只需要实现ISharingDbContext 这个接口就可以了如果需要事务在实现ISupportShardingTransaction
最终我们是通过实现一个抽象基类来继承abpdbcntext并且实现sharding-core需要的接口 AbstractShardingAbpDbContext 这样我们就可以在不破坏abp的同时又兼顾了sharding-core

注意:这边sharing-core让你们继承AbstractShardingDbContext是因为重复写这些接口的实现会很麻烦所以给你们写了一个抽象方便你们使用

abp集成注意事项

  • 通过源码可以看出abp集成需要赋值lazyserviceprovider 因为abp的dbcontext是交由uow自己处理并且需要支持很多特性所以我们在创建dbcontext的时候需要对此处进行赋值注意点。

  • 注意abp默认提供了IEntity<Guid>,IHasCreationTime属性较为常用所以我们需要注意如何支持这两种,因为当你用id取模分表或者创建时间分表的使用场景还是比较常见的所以我们需要支持。
    因为在insert时如果sharding-core发现对应的分表字段为null就无法继续执行下去,所以为了兼容abp需要支持两个比较常见的需求

赋值依赖注入支持domain event等事件

自动属性

了解sahrding-core针对dbcontext的分表支持

首先我们需要知道sharding-core是如何对一个普通的dbcontext进行支持的

如果你的dbcontext有用到以下任意一个接口那么集成起来可能需要自己去实现对应的接口

  • IDbSetSource 用来接管dbset

  • IQueryCompiler 用来接管查询编译

  • IDbContextTransactionManager 用来接管事务开启

  • IRelationalTransactionFactory 用来接管事务的提交、回滚 和加入

  • IModelCacheKeyFactory 用来接管dbcontext的模型缓存

  • IModelCustomizer 用来接管dbcontext的模型初始化前后自定义

如果你的efcore想接入sharding-core并且如果你没有对dbcontext的上述任何接口进行替换那么可以很容易就接入,如果你的efcore在创建的时候有针对上述的接口进行替换,就需要你自己手动进行两边的实现合并。

如何接入sharding-core

这边我们假设你没有对上述的dbcontextoptionbuilder的创建进行接口的替换那么你只需要进行如下操作就可以简单接入sharding-core

  • 首先就是默认创建dbcontext替换为sharding-core的配置

原先:

public void ConfigureServices(IServiceCollection services)services.AddDbContext<DefaultShardingTableDbContext>(o => o.UseSqlServer("Server=.;Database=TodoApp;Trusted_Connection=True"));

现在:

public void ConfigureServices(IServiceCollection services)//1.先检查dbcontext构造函数只允许 DbContextOptions<TodoAppDbContext> optionsShardingCoreHelper.CheckContextConstructors<DefaultShardingTableDbContext>();
//2.添加UseSharding<DefaultShardingTableDbContext>()让依赖注入创建的dbcontext支持查询插入事务的管理services.AddDbContext<DefaultShardingTableDbContext>(o=>o.UseSqlServer("Server=.;Database=TodoApp;Trusted_Connection=True").UseSharding<DefaultShardingTableDbContext>());
//3.添加分表配置new ShardingCoreConfigBuilder<DefaultShardingTableDbContext>(context.Services,((s, builder) =>{builder.UseSqlServer(s);} )).Begin(o =>{o.CreateShardingTableOnStart = false;o.EnsureCreatedWithOutShardingTable = false;o.AutoTrackEntity = true;}).AddShardingTransaction((connection, builder) =>builder.UseSqlServer(connection)).AddDefaultDataSource("ds0", "Server=.;Database=TodoApp;Trusted_Connection=True").AddShardingTableRoute(o =>{o.AddShardingTableRoute<ToDoItemVirtualTableRoute>();}).End();public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
//4.初始化分表配置var shardingBootstrapper = app.ApplicationServices.GetRequiredService<IShardingBootstrapper>();shardingBootstrapper.Start();

综上所述我们接入任何efcore的系统只需要进行4步(第一步都可以去掉只需要3步)就可以完美接入了,可以保证使用

abp正式接入替换

修改将todoitem表作为id取模来进行分表演示

修改TodoItem实体

默认TodoApp有一个TodoItem实体对象我们首先创建两个空接口

//标识对应分表对像的i分表字段是id,是自动创建的guidpublic interface IShardingKeyIsGuId{}
//标识对应的分表对应的分表字段是创建时间public interface IShardingKeyIsCreationTime{}
//修改TodoItempublic class TodoItem : BasicAggregateRoot<Guid>,IShardingTable,IShardingKeyIsGuId{[ShardingTableKey]public override Guid Id { get; protected set; }public string Text { get; set; }}

创建TodoItem的分表路由

通过继承默认分表取模路由AbstractSimpleShardingModKeyStringVirtualTableRoute

//id取模虽然是string但是guid也是一样的最多两位就是00_99,按5来取模public class ToDoItemVirtualTableRoute:AbstractSimpleShardingModKeyStringVirtualTableRoute<TodoItem>{public ToDoItemVirtualTableRoute() : base(2, 5){}}

实现抽象类修改TodoItemDbContext

实现 AbstractShardingAbpDbContext

public class TodoAppDbContext :AbstractShardingAbpDbContext<TodoAppDbContext>,IIdentityDbContext,ITenantManagementDbContext,IShardingTableDbContext

修改实体TodoItem

public class TodoItem : BasicAggregateRoot<Guid>,IShardingTable,IShardingKeyIsGuId{[ShardingTableKey]public override Guid Id { get; protected set; }public string Text { get; set; }}

其中别的接口都和sharding-core一致,为了支持abp的部分自动属性这边进行了新的接口添加用来标识当前的对象是通过什么方式来进行分表的,然后可以高效的通过接口来进行赋值,比如IShardingKeyIsGuId告诉系统是id为guid的进行分表的

public abstract class AbstractShardingAbpDbContext<TDbContext>...
{
......private void CheckAndSetShardingKeyThatSupportAutoCreate<TEntity>(TEntity entity) where TEntity : class{if (entity is IShardingKeyIsGuId){if (entity is IEntity<Guid> guidEntity){if (guidEntity.Id != default){return;}var idProperty = entity.GetProperty(nameof(IEntity<Guid>.Id));var dbGeneratedAttr = ReflectionHelper.GetSingleAttributeOrDefault<DatabaseGeneratedAttribute>(idProperty);if (dbGeneratedAttr != null && dbGeneratedAttr.DatabaseGeneratedOption != DatabaseGeneratedOption.None){return;}EntityHelper.TrySetId(guidEntity,() => GuidGenerator.Create(),true);}}else if (entity is IShardingKeyIsCreationTime){AuditPropertySetter?.SetCreationProperties(entity);}}
}

添加虚拟路由

既然你讲TodoItem进行了分表,那么你这边需要告诉系统你是按怎么个规则进行分表的,假设我们默认按id取模那么可以继承sharding-core默认提供的取模路由

public class ToDoItemVirtualTableRoute:AbstractSimpleShardingModKeyStringVirtualTableRoute<TodoItem>{public ToDoItemVirtualTableRoute() : base(2, 5){}}

简单说明就是分表后缀为2位数00-99,5代表模5也就是00,01,02,03,04
注意: IShardingTableDbContext如果dbcontext需要实现分表功能必须实现IShardingTableDbContext
到目前为止我们的准备工作已经完成了,接下来需要进行codefirst的支持和具体项目的配置使用了

选中TodoApp.EntityFrameworkCore项目打开TodoAppDbContextFactory替换dbcontext的创建方法,主要是替换codefirst的建表语句
这边是采用了EFCore.Sharding

static TodoAppDbContextFactory(){var services = new ServiceCollection();var configuration = BuildConfiguration();services.AddShardingDbContext<TodoAppDbContext>((conn, o) =>o.UseSqlServer(conn).ReplaceService<IMigrationsSqlGenerator, ShardingSqlServerMigrationsSqlGenerator<TodoAppDbContext>>()).Begin(o =>{o.AutoTrackEntity = true;}).AddShardingTransaction((connection, builder) =>builder.UseSqlServer(connection)).AddDefaultDataSource("ds0",configuration.GetConnectionString("Default")).AddShardingTableRoute(o =>{o.AddShardingTableRoute<ToDoItemVirtualTableRoute>();}).End();services.AddLogging();var buildServiceProvider = services.BuildServiceProvider();ShardingContainer.SetServices(buildServiceProvider);new ShardingBootstrapper(buildServiceProvider).Start();}public TodoAppDbContext CreateDbContext(string[] args){return ShardingContainer.GetService<TodoAppDbContext>();}

主要代码就是告诉efcore.tools如何创建对应的dbcontext
然后打开nuget控制台

选中需要生成迁移的项目

启动项设置为

执行命令

PM> Add-Migration InitTodoApp

PM> update-database

到此为止我们的code first已经完成了,系统会自动根据分表的配置来进行创建对应的sql语句

abp启动

因为sharding-core是基于接口和dbcontext所以只要你的efcore那么基本上你的生态就可以接入sharding-core,主要就是注意1点

  • 自定义替换DbContextOptions的部分服务

  • dbcontext的构造函数是DbContextOptions或者是他的泛型类

修改TodoAppEntityFrameworkCoreModule

public override void ConfigureServices(ServiceConfigurationContext context){......Configure<AbpDbContextOptions>(options =>{/* The main point to change your DBMS.* See also TodoAppDbContextFactory for EF Core tooling. */options.UseSqlServer();options.Configure<TodoAppDbContext>(context1 =>{context1.DbContextOptions.UseSqlServer("Server=.;Database=TodoApp;Trusted_Connection=True").UseSharding<TodoAppDbContext>();});});ShardingCoreHelper.CheckContextConstructors<TodoAppDbContext>();new ShardingCoreConfigBuilder<TodoAppDbContext>(context.Services,((s, builder) =>{builder.UseSqlServer(s);} )).Begin(o =>{o.CreateShardingTableOnStart = false;o.EnsureCreatedWithOutShardingTable = false;o.AutoTrackEntity = true;}).AddShardingTransaction((connection, builder) =>builder.UseSqlServer(connection)).AddDefaultDataSource("ds0", "Server=.;Database=TodoApp;Trusted_Connection=True").AddShardingTableRoute(o =>{o.AddShardingTableRoute<ToDoItemVirtualTableRoute>();}).End();}public override void OnPostApplicationInitialization(ApplicationInitializationContext context){context.ServiceProvider.GetRequiredService<IShardingBootstrapper>().Start();}

稍微解释下

options.Configure<TodoAppDbContext>(context1 =>{context1.DbContextOptions.UseSqlServer("Server=.;Database=TodoApp;Trusted_Connection=True").UseSharding<TodoAppDbContext>();});

用来告诉abp,TodoAppDbContext的创建需要使用useSharding,
之后就是sharding-core默认提供的builder,当然你们可以自行封装一下,别忘了在启动的时候

context.ServiceProvider.GetRequiredService<IShardingBootstrapper>().Start();

这个千万不能忘

运行TodoApp.Web


通过添加efcore的日志我们可以清晰地看到abp能够正确的将对应的数据插入进去,并且完全不需要修改现有代码,基本上的零基础使用,简单的配置,
如果您喜欢本库就点点star点点赞,来都来了点个推荐不过分吧。为.net生态做一份贡献,希望各位个多多提issue,和pr十分感激

项目demo

AbpVNextShardingTodoApp

Abp VNext 集成sharding-core 分表分库相关推荐

  1. asp.net mysql 读写分离_.NET Core实现分表分库、读写分离的通用 Repository功能

    首先声明这篇文章不是标题党,我说的这个类库是 FreeSql.Repository,它作为扩展库现实了通用仓储层功能,接口规范参考 abp vnext 定义,实现了基础的仓储层(CURD). 安装 d ...

  2. 基于 abp vNext 和 .NET Core 开发博客项目 - 集成Hangfire实现定时任务处理

    基于 abp vNext 和 .NET Core 开发博客项目 - 集成Hangfire实现定时任务处理 转载于:https://github.com/Meowv/Blog 接下来,将完成一个任务调度 ...

  3. .NETCore 下支持分表分库、读写分离的通用 Repository

    首先声明这篇文章不是标题党,我说的这个类库是 FreeSql.Repository,它作为扩展库现实了通用仓储层功能,接口规范参数 abp vnext,定义和实现基础的仓储层(CURD). 安装 do ...

  4. 基于 abp vNext 和 .NET Core 开发博客项目 - 数据访问和代码优先

    基于 abp vNext 和 .NET Core 开发博客项目 - 数据访问和代码优先 转载于:https://github.com/Meowv/Blog 本篇主要使用Entity Framework ...

  5. 基于 abp vNext 和 .NET Core 开发博客项目 - 完善与美化,Swagger登场

    基于 abp vNext 和 .NET Core 开发博客项目 - 完善与美化,Swagger登场 转载于:https://github.com/Meowv/Blog.git 在程序员界,总有一批强迫 ...

  6. 数据库中间件(分表分库路由)

    分区:对业务透明,分区只不过把存放数据的文件分成了许多小块,例如mysql中的一张表对应三个文件.MYD,MYI,frm. 根据一定的规则把数据文件(MYD)和索引文件(MYI)进行了分割,分区后的表 ...

  7. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(三)

    基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(三) 转载于:https://github.com/Meowv/Blog 上篇文章完成了分类和标签页面相关的共6个接 ...

  8. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(二)

    基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(二) 转载于:https://github.com/Meowv/Blog 上篇文章完成了两个接口:文章列表页.文章详 ...

  9. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(一)

    基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(一) 转载于:https://github.com/Meowv/Blog 现在博客数据库中的数据是比较混乱的,为了看 ...

最新文章

  1. 拼多多“砍价免费拿”始终差“0.09%”遭起诉,官方回应:活动真实
  2. java中使用bigdec,Java中的BigDecimal的使用
  3. 如何查询高考成绩2021年的成绩排位,2021年四川高考个人排名怎么查询,四川高考成绩排名查询方法...
  4. python程序实例电话本-利用Python电话本小程序!这波操作你给几分?
  5. sqlserver中GUID的默认值设置
  6. 大数据WEB阶段(七)JDBC、数据库批处理、数据库连接池
  7. _ASSERTE(_CrtIsValidHeapPointer(pUserData))错误详解
  8. java socket数据传输_Java Socket编程(一) Socket传输模式
  9. 「Python 编程」编码实现网络请求库中的 URL 解析器
  10. 【Flink】Flink exitCode=239
  11. 【面试题】面试问红黑树,我脸都绿了。。
  12. 今天很高兴,据说微软的长春的什么要设立在我们公司
  13. The servlet name already exists.解决方法
  14. json数据格式基础知识
  15. 域名解析:记录类型的含义
  16. linux HZ 值_Linux操作系统中进程的操作命令(ps,kill,keep)
  17. golang文件传输工具,支持大文件
  18. SpringBoot上传文件到服务器
  19. 数字锁相环matlab仿真,锁相环仿真_MATLAB仿真程序代码_二阶锁相环仿真过程
  20. Pandas requires version ‘2.0.1‘ or newer of ‘xlrd‘ (version ‘1.2.0‘ currently installed).

热门文章

  1. win7 绑定arp
  2. 10月Web服务器调查:Apache下降 Ngnix攀升
  3. 取消IE不允许下载文件的提示
  4. iTOP-4412开发板实现3路ADC数模转换驱动例程
  5. 解决“无法从套接字读取更多数据”
  6. 纯CSS制作各种各样的网页图标(三角形、暂停按钮、下载箭头、加号等)
  7. java 动态代理
  8. 14.6.3.1 The InnoDB Buffer Pool
  9. 现在是2016-09-23,查询2个月后的月份和入职的月份相同的数据
  10. Atitit。 《吠陀》 《梨俱吠陀》overview 经读后感  是印度上古时期一些文献的总称...