EF Core3.X实现水平分表
DataAccessHelper
一个基于EFCore的工具类,对EFCore中的context操作做了进一步的封装,且支持一个实体类映射多个数据表。
使用方法
如Demo中的例子所示,示例程序中一个Post实体类对应有多个Post数据表,多个数据表按年月存放不同的数据。数据表的命名规则为PostyyyyMM(如Post201910)。
1.新建数据表命名规则提供类,实现ITableMappable接口
// 数据表命名规则提供类,用于根据不同的条件映射不同的数据表 public class PostMapper : ITableMappable { // 根据条件返回对应的数据表名 public string GetMappingTableName(Type modelType, object condition) { string ret = ""; if (condition is DateTime date) { if (modelType == typeof(Post)) { // Format like Post201906 ret = $"Post{date.ToString("yyyyMM")}"; } } return ret; } }
2.你的DbContext类需要改动一些代码
请将你代码中的派生自DbContext类改为派生自ExtendDbContext,ExtendDbContext几乎不会改变任何DbContext的行为。
- 将你代码中的派生自DbContext类改为派生自ExtendDbContext
- 实现基类的构造方法,但可以什么都不干
- 把重写OnConfiguring的代码移到Configuring方法中进行重写
- 把重写OnModelCreating的代码移到ModelCreating方法中进行重写
// step1:派生自ExtendDbContext public partial class BloggingContext : ExtendDbContext { public virtual DbSet<Blog> Blog { get; set; } public virtual DbSet<Post> Post { get; set; } // step2:实现基类的构造方法,但可以什么都不干 public BloggingContext() { } // step2:实现基类的构造方法,但可以什么都不干 public BloggingContext(ICollection<TableMappingRule> rules):base(rules) { } private static string ConnectString { get; set; } public static void SetConnectString(string conStr) { ConnectString = conStr; } // step3:把重写OnConfiguring的代码移到Configuring方法中进行重写 protected override void Configuring(DbContextOptionsBuilder optionsBuilder) { if (!optionsBuilder.IsConfigured) { optionsBuilder.UseSqlite(ConnectString) .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); } } // step4:把重写OnModelCreating的代码移到ModelCreating方法中进行重写 protected override void ModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>(entity => { entity.HasKey(e => e.BlogId); entity.ToTable("Blog"); entity.Property(e => e.BlogId).ValueGeneratedNever(); entity.Property(e => e.Url).HasColumnType("VARCHAR (1024)"); }); modelBuilder.Entity<Post>(entity => { entity.HasKey(e => e.PostId); entity.ToTable("Post"); entity.Property(e => e.PostId).ValueGeneratedNever(); entity.Property(e => e.Content).HasColumnType("VARCHAR (1024)"); entity.Property(e => e.PostDate) .IsRequired() .HasColumnType("DATETIME"); entity.Property(e => e.Title).HasColumnType("VARCHAR (512)"); entity.HasOne(e => e.Blog) .WithMany(b => b.Posts) .HasForeignKey(e => e.BlogId); }); } }
3.正式使用
// 使用示例 static void TestChangeTable(DataAccessor dal, ITableMappable mapper) { // 数据表映射条件 DateTime sept = DateTime.Parse("2019-09-05"); DateTime oct = DateTime.Parse("2019-10-05"); // 切换Post实体类的映射的数据表,切换条件为2019年10月,理论上应该切换为数据表 "Post201910" dal.ChangeMappingTable(typeof(Post), mapper, oct); // 查询该表下的所有数据 List<Post> octData = dal.GetAll<Post>().ToList(); Console.WriteLine("Oct. data"); foreach (Post item in octData) { Console.WriteLine(item); } // 切换Post实体类的映射的数据表,切换条件为2019年9月,理论上应该切换为数据表 "Post201909" dal.ChangeMappingTable(typeof(Post), mapper, sept); // 查询该表下的所有数据 List<Post> septData = dal.GetAll<Post>().ToList(); Console.WriteLine("Sept. data"); foreach (Post item in septData) { Console.WriteLine(item); } }
转载自:https://github.com/YinRunhao/DataAccessHelper/tree/EFCore31