Abp VNext 集成sharding-core 分表分库

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是因为重复写这些接口的实现会很麻烦所以给你们写了一个抽象方便你们使用

b49873b6342ee61408bc523504e6171d.png

abp集成注意事项

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

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

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

df93fda523021bf1367f79cb17886740.png

自动属性

cbf3322530f9ddc2ae1fbb4cead33b24.png

了解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控制台
35f569431392ac0d79b958cf08c9ab09.png
选中需要生成迁移的项目
44211be74a891f56254bec5af2b10454.png
启动项设置为
b99f80873308960b3069d9d5a153877d.png

执行命令

PM> Add-Migration InitTodoApp

ddfd25602c3391a8a28ba9d0bc085fae.png

PM> update-database

783fc062a1a25c313e1b712edc510e88.png

到此为止我们的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

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

项目demo

AbpVNextShardingTodoApp

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/296457.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

引热议!多所高校明文规定:不再给部分全日制研究生安排宿舍

全世界只有3.14 % 的人关注了爆炸吧知识本文转自募格学术。近日&#xff0c;高校宿舍问题频发。矛盾点基本都集中在宿舍加塞人&#xff0c;宿舍环境不好&#xff0c;为了迎接新生强制老生搬宿舍但宿舍环境一言难尽等...... 不过好歹也都算解决了研究生住宿的问题。但近日&#…

Unity 游戏开发技巧集锦之使用忍者飞镖创建粒子效果

Unity 游戏开发技巧集锦之使用忍者飞镖创建粒子效果 使用忍者飞镖创建粒子效果 游戏中&#xff0c;诸如烟、火、水滴、落叶等粒子效果&#xff0c;都可以使用粒子系统&#xff08;particle system&#xff09;来实现。例如&#xff0c;《明朝传奇》中的篝火&#xff0c;如图2-3…

落在我手里,今天你能嫁出去算我输!

1 今天你能嫁出去算我输▼2 好像拍到了某些不可描述的画面▼3 猫猫&#xff1a;人呢&#xff1f;掉哪儿了&#xff1f;▼4 像极了下决心运动的你▼5 据最新研究欲火焚身这个词是很有科学依据的▼6 按这么说至少能保证说上话▼7 这不是普通狗仔了已经是海狗仔了▼你点的每…

记一次 .NET 某资讯论坛 CPU爆高分析

大概有11天没发文了&#xff0c;真的不是因为懒&#xff0c;本想前几天抽空写&#xff0c;不知道为啥最近求助的朋友比较多&#xff0c;一天都能拿到2-3个求助dump&#xff0c;晚上回来就是一顿分析&#xff0c;有点意思的是大多朋友自己都分析了几遍或者公司多年的牛皮藓问题&…

内存调试技巧

内存调试技巧 2007 年 6 月 21 日 本文将带您了解一些良好的和内存相关的编码实践&#xff0c;以将内存错误保持在控制范围内。内存错误是 C 和 C 编程的祸根&#xff1a;它们很普遍&#xff0c;认识其严重性已有二十多年&#xff0c;但始终没有彻底解决&#xff0c;它们可能严…

数学课本上的几大变态之处

全世界只有3.14 % 的人关注了爆炸吧知识数学课本上的几大变态--完--

使用Redis set 解决数据的唯一性问题

前言最近遇到一个问题&#xff0c;就是接收第三方数据的时候&#xff0c;类似这种直播数据&#xff0c;由于业务的缘故&#xff0c;导致对方给的数据每次都是全量的&#xff0c;而且请求很频繁&#xff0c;有时候一秒好几十次。直播数据一般都是刷刷刷的&#xff0c;这个大家或…

mysql集群从节点无法启动_一次galera cluster集群故障节点无法启动问题排查

现象环境&#xff1a;Server version: 10.0.25-MariaDB-wsrep MariaDB Server, wsrep_25.13.raf7f02e配置文件&#xff1a;[rootnode-23 mariadb]# more /etc/my.cnf[mysqld]server_id3bind_address node-23port 3306datadir/var/lib/mysqllog-error/var/log/mariadb/mariadb…

webform 页面传值的方法总结

ASP.NET页面之间传递值的几种方式 页面传值是学习asp.net初期都会面临的一个问题&#xff0c;总的来说有页面传值、存储对象传值、ajax、类、model、表单等。但是一般来说&#xff0c;常用的较简单有QueryString&#xff0c;Session&#xff0c;Cookies&#xff0c;Application…

iNeuOS工业互联网操作系统,智慧用电测控应用案例

目 录1. 概述... 22. 系统部署结构... 23. 用电测控终端... 34. 系统应用介绍... 61. 概述通过物联网技术对引发电气火灾的主要因素(导线温度、电流和漏电流等)进行不间断的数据跟踪与统计分析&#xff0c;实时发现电气线路和用电设备存在的安全隐…

出现了!豆瓣最高9.9分,2020年最值得看的美剧!你居然还没看过?【内附资源】...

全世界只有3.14 % 的人关注了爆炸吧知识在调性普遍黄暴烧脑的美剧大流中&#xff0c;《This is us》没有大牌主演&#xff0c;没有炫酷特效&#xff0c;却让观众集体沦陷&#xff0c;被称为5年难得一见的美剧。有人说&#xff0c;这是「有生之年看过的最温柔的美剧」。但它取得…

C# 修改配置文件进行窗体logo切换

01—前言&#xff1a;题外的话大家可能发现这个号现在原创越来越少了&#xff0c;其实小编并没有放弃持续更新&#xff0c;只是把一手原创放到了 【dotnet编程大全】这个号了&#xff0c;那个号目前原创主要更新的是wpf mvvm方面的知识&#xff0c;框架用的Caliburn.Micro&…

数学有趣地超乎你的想象

全世界只有3.14 % 的人关注了爆炸吧知识说起数学你是拒绝还是喜欢看完这一组&#xff0c;对于数学他的震撼、霸气、美来感受下哇1三角形内角和为1802多边形外角和为360&#xff08;图来源于可乐学习&#xff09;3怎样将一个正三角形剪拼成正方形&#xff1f;4怎样把两正方形剪拼…

使用C#像google/zx一样编写脚本

google/zxzx是谷歌开源的一个能够帮助开发者快速编写脚本的工具&#xff0c;它使用JavaScript作为编程语言。示例脚本如下&#xff1a;#!/usr/bin/env zxawait $cat package.json | grep namelet branch await $git branch --show-current await $dep deploy --branch${branch…

redis 查询缓存_Redis缓存总结:淘汰机制、缓存雪崩、数据不一致....

在实际的工作项目中&#xff0c; 缓存成为高并发、高性能架构的关键组件 &#xff0c;那么Redis为什么可以作为缓存使用呢&#xff1f;首先可以作为缓存的两个主要特征&#xff1a;在分层系统中处于内存/CPU具有访问性能良好&#xff0c;缓存数据饱和&#xff0c;有良好的数据淘…

5部适合学英语的动画电影,快和孩子一起看!

全世界只有3.14 % 的人关注了爆炸吧知识今天我们与大家分享5部非常适合小学生学习英语的动画电影&#xff0c;家长们可依据不同类别和主题为孩子挑选喜欢的影片&#xff0c;在家陪孩子一起观看。文末可免费领取哦~01 《丁丁历险记》讲述的是一天丁丁买了一只古老的船模送给船长…

OC面向对象—封装

OC面向对象—封装 一、面向对象和封装 面向对象的三大特性&#xff1a;封装&#xff08;成员变量&#xff09;、继承和多态 在OC语言中&#xff0c;使用interface和implementation来处理类。 interface就好像暴露在外面的时钟表面&#xff0c;像外界提供展示以及接口。implemen…

10张让你大脑崩溃的图,敢接受挑战吗?

全世界只有3.14 % 的人关注了爆炸吧知识快睡了吧&#xff1f;来做一组视觉游戏~一些人热爱挑战各种错觉&#xff0c;如果你也是这类型图片的粉丝&#xff0c;这10张图片会让你非常过瘾&#xff01;入门篇【挑战一】在这张图片中&#xff0c;你能看到几个红球&#xff1f;5个&am…

Source Generator 单元测试

Source Generator 单元测试IntroSource Generator 是 .NET 5.0 以后引入的一个在编译期间动态生成代码的一个机制&#xff0c;介绍可以参考 C# 强大的新特性 Source GeneratorGetStarted使用起来还算比较简单的&#xff0c;我平时一般用 xunit&#xff0c;所以下面的示例也是使…

又一个中国男人荣获巨奖!拿奖拿的手软,却坦言“我对诺奖没有兴趣”...

全世界只有3.14 % 的人关注了爆炸吧知识获得诺奖似乎只是时间问题2020年9月10日&#xff0c;2021年科学突破奖&#xff08; BREAKTHROUGH PRIZES&#xff09;正式公布。来自中国香港的科学家卢煜明获得了生命科学科学突破奖&#xff0c;华人数学家孙崧获得了数学新视野奖。前几…