.net core 使用 ShardingCore 按尾号分表(二)
上一篇文章 是按时间分表 这篇 是 按尾号分表 例如 00 01 02 上一篇文章 也没做数据迁移的测试 这一篇做一下
在上一篇文章 中 有Order 我新增一个Product 一个订单可以对应多个商品 ,一个商品可以被多人下单购买 那么就是多对多关系
但是这个关系 数据库分库分表后 就无法有效对应 也就是说不能像之前 写
public ICollection<OrderProduct> OrderProducts { get; set; } 这种方式
我这里是建立了一个中间表
public class Order { [Key] public string Id { get; set; } public string Payer { get; set; } public long Money { get; set; } public string Area { get; set; } public OrderStatusEnum OrderStatus { get; set; } public string UserId { get; set; } public DateTime CreationTime { get; set; } } public enum OrderStatusEnum { NoPay = 1, Paying = 2, Payed = 3, PayFail = 4 }
public class OrderProduct { [Key] public string Id { get; set; } public string ProductId { get; set; } public string OrderId { get; set; } }
public class Product { [Key] public string Id { get; set; } public string Name { get; set; } }
这是按尾号分表
public class OrderProductVirtualTableRoute : AbstractSimpleShardingModKeyStringVirtualTableRoute<OrderProduct> { public OrderProductVirtualTableRoute() : base(2, 3) { } public override void Configure(EntityMetadataTableBuilder<OrderProduct> builder) { //设置分表字段 builder.ShardingProperty(o => o.Id); //是否启动的时候创建表,仅在启动时判断该属性, //如果你是按时间分表的那么这个属性将不会在特定时间创建对应的表信息需要手动进行表创建和添加 //当然您也可以使用系统默认的时间路由,通过重写AutoCreateByT builder.AutoCreateTable(null); //分割符 builder.TableSeparator("_"); } }
这是按时间分表
public class OrderVirtualTableRoute : AbstractSimpleShardingMonthKeyDateTimeVirtualTableRoute<Order> { public override DateTime GetBeginTime() { return new DateTime(2023, 5, 1); } //注意一定要配置或者采用接口+标签也是可以的 public override void Configure(EntityMetadataTableBuilder<Order> builder) { builder.ShardingProperty(o => o.CreationTime); } public override bool AutoCreateTableByTime() { return true; } }
这是按尾号分表
public class ProductVirtualTableRoute : AbstractSimpleShardingModKeyStringVirtualTableRoute<Product> { // 2 为 尾号两位 3 为分3个表 public ProductVirtualTableRoute() : base(2, 3) { } public override void Configure(EntityMetadataTableBuilder<Product> builder) { //设置分表字段 builder.ShardingProperty(o => o.Id); //是否启动的时候创建表,仅在启动时判断该属性, //如果你是按时间分表的那么这个属性将不会在特定时间创建对应的表信息需要手动进行表创建和添加 //当然您也可以使用系统默认的时间路由,通过重写AutoCreateByT builder.AutoCreateTable(null); //分割符 builder.TableSeparator("_"); } }
依赖注入 配置
builder.Services.AddShardingDbContext<MyDbContext>().UseRouteConfig(op => { //添加OrderProduct表虚拟路由 op.AddShardingTableRoute<OrderProductVirtualTableRoute>(); //添加order表虚拟路由 op.AddShardingTableRoute<OrderVirtualTableRoute>(); //添加Product表虚拟路由 op.AddShardingTableRoute<ProductVirtualTableRoute>(); }).UseConfig(op => { ILoggerFactory factory = LoggerFactory.Create(config => { config.AddConsole(); }); op.UseShardingMigrationConfigure(b => { //数据迁移 b.ReplaceService<IMigrationsSqlGenerator, ShardingMySqlMigrationsSqlGenerator>(); }); op.ThrowIfQueryRouteNotMatch = false; op.UseShardingQuery((conStr, builder) => { //查询 builder.UseMySql(conStr, MySqlServerVersion.AutoDetect(conStr)).UseLoggerFactory(factory); }); op.UseShardingTransaction((connection, builder) => { //事务 builder.UseMySql(connection, MySqlServerVersion.AutoDetect(connection.ConnectionString)).UseLoggerFactory(factory); }); //默认数据源 op.AddDefaultDataSource("ds0", "Data Source=192.168.0.192;Initial Catalog=test;uid=root;pwd=123456;"); op.AddReadWriteSeparation(sp => { return new Dictionary<string, IEnumerable<string>>() { { "ds0", new List<string>() { "Data Source=192.168.0.192;Initial Catalog=test;uid=root;pwd=123456;" } } }; }, ReadStrategyEnum.Loop, defaultEnable: true); }).AddShardingCore();
这是中间件
//建议补偿表在迁移后面 using (var scope = app.Services.CreateScope()) { var myDbContext = scope.ServiceProvider.GetService<MyDbContext>(); //如果没有迁移那么就直接创建表和库 //myDbContext.Database.EnsureCreated(); //如果有迁移使用下面的 myDbContext.Database.Migrate(); } //not required, enable check table missing and auto create,非必须 启动检查缺少的表并且创建 app.Services.UseAutoTryCompensateTable(); //种子数据 app.InitSeed();
测试结果