1、新建Asp.Net Core WebApi项目
这里使用Visual Studio 2022,Asp.Net Core WebApi项目,.Net6框架开发分表功能
2、插件安装
使用nuget命令安装或者离线安装
PM> Install-Package ShardingCore -Version 7.7.1.7
PM> Install-Package Pomelo.EntityFrameworkCore.MySql -Version 7.0.0-alpha.1
3、准备数据库实体类
订单类
public class Order
{
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 DateTime CreationTime { get; set; }
}
用户类
public class SysUser
{
public string Id { get; set; }
public string Name { get; set; }
public string SettingCode { get; set; }
public string Area { get; set; }
}
设置类
public class Setting
{
public string Code { get; set; }
public string Name { get; set; }
}
订单状态枚举
public enum OrderStatusEnum
{
NoPay=1,
Paying=2,
Payed=3,
PayFail=4
}
4、分表路由配置类
订单分表路由配置类,按订单产生的日期月份自动分表
///
/// 按月份自动分表
///
public class OrderVirtualTableRoute : AbstractSimpleShardingMonthKeyDateTimeVirtualTableRoute
{
public override bool AutoCreateTableByTime()
{
return true;
}
public override void Configure(EntityMetadataTableBuilder builder)
{
builder.ShardingProperty(o => o.CreationTime);//按创建时间字段分表
}
public override DateTime GetBeginTime()
{
return new DateTime(2021,1,1);
}
}
用户信息分表路由配置类,按照用户id取模3分表
///
/// 用户表按照id取模3分表
///
public class SysUserVirtualTableRoute : AbstractSimpleShardingModKeyStringVirtualTableRoute
{
public SysUserVirtualTableRoute():base(2,3)
{
}
public override void Configure(EntityMetadataTableBuilder builder)
{
builder.ShardingProperty(o => o.Id);
}
}
5、数据库上下文类
负责维护数据库上下文信息,可配置实体与数据库表的对应关系
public class MyDbContext : AbstractShardingDbContext, IShardingTableDbContext
{
public MyDbContext(DbContextOptions options):base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity(entity =>
{
entity.HasKey(o => o.Id);
entity.Property(o => o.Id).IsRequired().IsUnicode(false).HasMaxLength(50);
entity.Property(o => o.Payer).IsRequired().IsUnicode(false).HasMaxLength(50);
entity.Property(o => o.Area).IsRequired(false).IsUnicode(false).HasMaxLength(50);
entity.Property(o => o.OrderStatus).HasConversion();
entity.ToTable(nameof(Order));
});
modelBuilder.Entity(entity =>
{
entity.HasKey(o => o.Id);
entity.Property(o => o.Name).IsRequired().IsUnicode(false).HasMaxLength(50);
entity.Property(o => o.Area).IsRequired(false).IsUnicode(false).HasMaxLength(50);
entity.Property(o => o.SettingCode).IsRequired().IsUnicode(false).HasMaxLength(50);
entity.ToTable(nameof(SysUser));
});
modelBuilder.Entity(entity =>
{
entity.HasKey(o => o.Code);
entity.Property(o => o.Code).IsRequired().IsUnicode(false).HasMaxLength(50);
entity.Property(o => o.Name).IsRequired().IsUnicode(false).HasMaxLength(50);
entity.ToTable(nameof(Setting));
});
}
public IRouteTail RouteTail { get; set; }
}
6、启动类的配置
using Microsoft.EntityFrameworkCore;
using ShardingCore;
using ShardingCore.Sharding.ReadWriteConfigurations;
using ShardingTableDemo;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddShardingDbContext().UseRouteConfig(op =>
{
op.AddShardingTableRoute();
op.AddShardingTableRoute();
}).UseConfig(op =>
{
op.ThrowIfQueryRouteNotMatch = false;
op.UseShardingQuery((conStr, bd) =>
{
bd.UseMySql(conStr, new MySqlServerVersion(new Version())).UseLoggerFactory(StartupExtension.efLogger);
});
op.UseShardingTransaction((connection, bd) =>
{
bd.UseMySql(connection, new MySqlServerVersion(new Version())).UseLoggerFactory(StartupExtension.efLogger);
});
op.AddDefaultDataSource("ds0", "Server=127.0.0.1;port=3306;user=root;password=xxx1990;database=yzwDb1;");
op.AddReadWriteSeparation(sp =>
{
return new Dictionary>
{
{"ds0",new List()
{
"Server=127.0.0.1;port=3306;user=root;password=xxx1990;database=yzwDb1;"
}
}
};
}, ReadStrategyEnum.Loop, true);
}).AddShardingCore();
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
var app = builder.Build();
app.UseAuthorization();
app.MapControllers();
using(var scope = app.Services.CreateScope())
{
var myDbContext = scope.ServiceProvider.GetService();
myDbContext.Database.EnsureCreated();
}
app.Services.UseAutoTryCompensateTable();
app.InitSeed();
app.Run();
7、数据库初始化
public static class StartupExtension
{
public static ILoggerFactory efLogger = LoggerFactory.Create(builder =>
{
builder.AddFilter((category, level) => category == DbLoggerCategory.Database.Command.Name && level == LogLevel.Debug).AddConsole();
});
public static void InitSeed(this IApplicationBuilder app)
{
using(var servciceScope = app.ApplicationServices.CreateScope())
{
var myDbContext = servciceScope.ServiceProvider.GetRequiredService();
if(!myDbContext.Set().Any())
{
List settings = new List(3);
settings.Add(new Setting()
{
Code="Admin",
Name= "AdminName"
});
settings.Add(new Setting()
{
Code="User",
Name="UserName"
}
);
settings.Add(new Setting()
{
Code="SuperAdmin",
Name="SuperAdminName"
});
List users = new List(10);
for (int i = 0; i < 10; i++)
{
var user = new SysUser() {
Id=i.ToString(),
Name=$"MyName{i}",
SettingCode = settings[i%3].Code
};
users.Add(user);
}
List orders = new List(300);
var begin = new DateTime(2021, 1, 1, 3, 3, 3);
for (int i = 0; i < 300; i++)
{
var order = new Order()
{
Id=i.ToString(),
Payer = $"{i%10}",
Money = 100+new Random().Next(100,3000),
OrderStatus = (OrderStatusEnum)(i%4+1),
CreationTime = begin.AddDays(i)
};
orders.Add(order);
}
myDbContext.AddRange(settings);
myDbContext.AddRange(users);
myDbContext.AddRange(orders);
myDbContext.SaveChanges();
}
}
}
}
8、启动程序,查看数据库
9、新建OrderController,测试查询、修改、删除接口
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace ShardingTableDemo.Controllers
{
[ApiController]
[Route("[controller]")]
public class OrderController:ControllerBase
{
private MyDbContext dbContext;
public OrderController(MyDbContext myDbContext)
{
this.dbContext = myDbContext;
}
[Route("Query")]
public async Task Query()
{
var sysUser = await this.dbContext.Set().Where(o => o.Id == "1").FirstOrDefaultAsync();
var dateTime = new DateTime(2021, 3, 5);
var order = await this.dbContext.Set().Where(o => o.CreationTime >= dateTime).OrderBy(o => o.CreationTime).FirstOrDefaultAsync();
var orderIdOne = await this.dbContext.Set().FirstOrDefaultAsync(o => o.Id == "3");
var sysUsers = await this.dbContext.Set().Where(o => o.Id == "1" || o.Id == "6").ToListAsync();
return Ok(new object[]
{
sysUser,
order,
orderIdOne,
sysUsers
});
}
[Route("QueryJoin1")]
//分表与普通表之间的join查询
public async Task QueryJoin1()
{
var sql = from user in this.dbContext.Set().Where(o => o.Id == "1" || o.Id == "6")
join setting in this.dbContext.Set()
on user.SettingCode equals setting.Code
select new
{
user.Id,
user.Name,
user.Area,
user.SettingCode,
SettingName = setting.Name
};
return Ok(await sql.ToListAsync());
}
[Route("QueryJoin2")]
//分表与分表之间的join查询
public async Task QueryJoin2()
{
var begin = new DateTime(2021, 3, 2);
var end = new DateTime(2021, 4, 3);
var sql1 = from user in this.dbContext.Set().Where(o => o.Id == "1" || o.Id == "6")
join order in this.dbContext.Set().Where(o => o.CreationTime >= begin && o.CreationTime <= end)
on user.Id equals order.Payer
select new
{
user.Id,
user.Name,
user.Area,
user.SettingCode,
OrderId=order.Id,
order.Payer,
order.CreationTime
};
return Ok(await sql1.ToListAsync());
}
///
/// 使用EFCore追踪式修改,只更改变化了的字段
///
///
[Route("Update")]
public async Task Update()
{
var sysUser = await this.dbContext.Set().Where(o => o.Id == "1").FirstOrDefaultAsync();
sysUser.Name = "new name";
var i = await this.dbContext.SaveChangesAsync();
return Ok(i);
}
///
/// 非追踪式修改,全部字段更新
///
///
[Route("UpdateNoTracking")]
public async Task UpdateNoTracking()
{
var sysUser = await this.dbContext.Set().AsNoTracking().Where(o => o.Id == "1").FirstOrDefaultAsync();
sysUser.Name = "new name";
this.dbContext.Update(sysUser);
var i = await this.dbContext.SaveChangesAsync();
return Ok(i);
}
[Route("Delete")]
public async Task Delete()
{
var sysUser = await this.dbContext.Set().Where(o => o.Id == "9").FirstOrDefaultAsync();
this.dbContext.Remove(sysUser);
var i = await this.dbContext.SaveChangesAsync();
return Ok(i);
}
}
}
参考内容:初始化 | ShardingCore文档