百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Abp VNext 分表分库ShardingCore(分库分表查询排序)

ccwgpt 2024-09-20 13:35 34 浏览 0 评论

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


Gitee Star 助力dotnet 生态 Github Star


背景

你是否在使用efcore,你是否在使用abp,你是否对目前的分表十分厌恶,手动指定表让你的代码无辜多出很多胶水代码,那么这次的文章可以很好的帮你解决掉当前的困难点,sharding-core 针对efcore的分库分表读写分离的痛点进行扩展,可以完美集成到efcore生态的系统里面,无论你是abp还是其他使用efcore的框架,你确定真的不看一下吗,如何集成abp当时我发布这个库的时候就有很多人问我是否支持,我的回答是支持的,只是个人没有时间去实现。这次已经实现了我这边将分享下如何集成sharding-core到abp 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> options
            ShardingCoreHelper.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,是自动创建的guid
    public interface IShardingKeyIsGuId
    {
    }
//标识对应的分表对应的分表字段是创建时间
    public interface IShardingKeyIsCreationTime
    {
    }
//修改TodoItem
    public 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十分感激

相关推荐

用Deepseek扩写土木工程毕业论文实操指南

用Deepseek扩写毕业论文实操指南一、前期准备整理现有论文初稿/提纲列清楚论文核心框架(背景、现状、意义、方法、数据、结论等)梳理好关键文献,明确核心技术路线二、Deepseek扩写核心思路...

985学霸亲授,DeepSeek也能绘6大科研图表,5分钟就出图

在实验数据处理中,高效可视化是每个科研人的必修课。传统绘图软件操作复杂、耗时费力,而智能工具DeepSeek的出现彻底改变了这一现状。本文将详解如何用DeepSeek一键生成六大科研常用图表,从思维导...

AI写论文刷屏?大学生正在丢掉的思考力

一、宿舍深夜:当论文变成"Ctrl+C+V"凌晨两点的大学宿舍,小王对着电脑屏幕叹气。本该三天前开始写的近代史论文,此刻还一片空白。他熟练打开某AI写作网站,输入"论五四运动的...

Grok在辅助论文写作上能不能既“聪明”又“可怕”?!

AcademicIdeas-学境思源AI初稿写作随着人工智能技术的飞速发展,论文写作这一学术任务正迎来新的助力。2025年2月18日,美国xAI公司推出了备受瞩目的Grok3模型,其创始人埃隆·...

大四论文沟通场景!音频转文字难题听脑AI来化解

大四学生都知道,写论文时和导师沟通修改意见,简直是“过关斩将”。电话、语音沟通完,想把导师说的修改方向、重点要求记下来,麻烦事儿可不少。手写记不全,用普通录音转文字工具,转完还得自己慢慢找重点,稍不注...

论文写作 | 技术路线图怎么画?(提供经典优秀模板参考)

技术路线图是一种图表或文字说明,用于描述研究目标、方法和实施计划。它展示了研究的整体框架和步骤,有助于读者理解研究的逻辑和进展。在课题及论文中,技术路线图是常见的一部分,甚至是一个类似心脏一样的中枢器...

25年信息系统项目管理师考试第2批论文题目写作建议思路框架

25年信息系统项目管理师考试第2批论文题目写作建议思路框架--马军老师

微信购物应尽快纳入法律框架(微信购物管辖)

符向军近日,甘肃省工商行政管理局发布《2016年上半年信息分析报告》。报告显示,微信网购纠纷迅猛增长,网络购物投诉呈上升趋势。投诉的主要问题有出售的商品质量不过关、消费者通过微信付款后对方不发货、购买...

泛珠三角区域网络媒体与腾讯微信签署《战略合作框架协议》

新海南客户端、南海网7月14日消息(记者任桐)7月14日上午,参加第四届泛珠三角区域合作网络媒体论坛的区域网络媒体负责人及嘉宾一行到腾讯微信总部座谈交流,并签署《战略合作框架协议》(以下简称《框架协...

离线使用、植入微信-看乐心Mambo手环如何打破框架

从2014年开始智能手环就成功进入人们的生活,至今已经演变出数据监测、信息推送、心率监测等诸多五花八门的功能,人们选择智能手环并不指望其能够改变身体健康情况,更多的是通过数据来正视自身运动情况和身体健...

微信私域电商运营策略与框架(微信私域怎么做)

...

华专网络:如何零基础制作一个网站出来?

#如何零基础制作一个网站出来?#你是不是觉得网站建设很复杂,觉得自己是小白,需求不明确、流程搞不懂、怕被外包公司坑……这些问题我都懂!今天华专网络就用大白话给你捋清楚建站的全流程,让你轻松get网站制...

WAIC2024丨明日上午9点,不见不散!共同探讨智能社会与全球治理框架

大咖云集,硕果闪耀WAIC2024世界人工智能大会智能社会论坛将于7月5日9:00-12:00与你相约直播间WAIC2024上海杨浦同济大学哔哩哔哩多平台同步直播探讨智能社会与全球治理框架WAIC...

约基奇:森林狼换来戈贝尔时大家都在嘲笑 他们的阵容框架很不错

直播吧5月4日讯西部季后赛半决赛,掘金将迎战森林狼,约基奇赛前接受采访。约基奇说道:“当蒂姆-康纳利(森林狼总经理、前掘金总经理&曾选中约基奇)做了那笔交易(换来戈贝尔)时,每个人都在嘲笑他...

视频号带货为什么一个流量都没有?顶级分析框架送给你

视频号带货为什么一个流量都没有?遇到问题,一定是步步来分析内容,视频号带货一个流量都没有,用另外一个意思来讲,就可以说是零播放。为什么视频号带货一个流量都没有?跟你说再多,都不如来个分析框架。1、是否...

取消回复欢迎 发表评论: