From d02fb7260327c1818a9058633721a70c3fb54a46 Mon Sep 17 00:00:00 2001 From: xuejiaming <326308290@qq.com> Date: Thu, 7 Oct 2021 10:00:59 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=B9=B6=E4=B8=94=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E4=BF=AE=E5=A4=8Defcore=E7=9A=84code=20first=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0readme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 80 ++++++------ .../DefaultDesignTimeDbContextFactory.cs | 7 +- .../EFCores/ShardingWithMod.cs | 7 ++ ...05204_EFCoreShardingAddTextStr.Designer.cs | 93 ++++++++++++++ ...20211007005204_EFCoreShardingAddTextStr.cs | 25 ++++ ...0210_EFCoreShardingAddTextStr1.Designer.cs | 100 +++++++++++++++ ...0211007010210_EFCoreShardingAddTextStr1.cs | 25 ++++ ...1252_EFCoreShardingAddTextStr2.Designer.cs | 107 ++++++++++++++++ ...0211007011252_EFCoreShardingAddTextStr2.cs | 25 ++++ ...aultShardingTableDbContextModelSnapshot.cs | 21 ++++ samples/Sample.Migrations/readme.md | 117 ++++++++++++++++++ src/ShardingCore/Helpers/MigrationHelper.cs | 30 +++-- 12 files changed, 585 insertions(+), 52 deletions(-) create mode 100644 samples/Sample.Migrations/Migrations/ShardingMigrations/20211007005204_EFCoreShardingAddTextStr.Designer.cs create mode 100644 samples/Sample.Migrations/Migrations/ShardingMigrations/20211007005204_EFCoreShardingAddTextStr.cs create mode 100644 samples/Sample.Migrations/Migrations/ShardingMigrations/20211007010210_EFCoreShardingAddTextStr1.Designer.cs create mode 100644 samples/Sample.Migrations/Migrations/ShardingMigrations/20211007010210_EFCoreShardingAddTextStr1.cs create mode 100644 samples/Sample.Migrations/Migrations/ShardingMigrations/20211007011252_EFCoreShardingAddTextStr2.Designer.cs create mode 100644 samples/Sample.Migrations/Migrations/ShardingMigrations/20211007011252_EFCoreShardingAddTextStr2.cs create mode 100644 samples/Sample.Migrations/readme.md diff --git a/README.md b/README.md index 124c04ab..105b8515 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ Oracle | 支持 | 未测试 - [默认路由](#默认路由) - [Api](#Api) - [高级配置](#高级配置) + - [code-first](#code-first) - [自动追踪](#自动追踪) - [手动路由](#手动路由) - [自动建表](#自动建表) @@ -549,43 +550,9 @@ AbstractSimpleShardingYearKeyLongVirtualTableRoute |按时间戳 |yyyy | `>,>=,< # 高级 -## 批量操作 +## code-first +目前`sharding-core`已经支持code first支持代码现行,具体实现可以参考[Migrations](https://github.com/xuejmnet/sharding-core/tree/main/samples/Sample.Migrations/readme.md) -批量操作将对应的dbcontext和数据进行分离由用户自己选择第三方框架比如[`Z.EntityFramework.Plus.EFCore`](https://github.com/zzzprojects/EntityFramework-Plus) 进行批量操作或者 [`EFCore.BulkExtensions`](https://github.com/borisdj/EFCore.BulkExtensions) ,支持一切三方批量框架 -```c# -var list = new List(); -///通过集合返回出对应的k-v归集通过事务开启 - var dbContexts = _defaultTableDbContext.BulkShardingEnumerable(list); - - - foreach (var dataSourceMap in dbContexts) - { - foreach (var tailMap in dataSourceMap.Value) - { - tailMap.Key.BulkInsert(tailMap.Value.ToList()); - //tailMap.Key.BulkDelete(tailMap.Value.ToList()); - //tailMap.Key.BulkUpdate(tailMap.Value.ToList()); - } - } - _defaultTableDbContext.SaveChanges(); - //or - var dbContexts = _defaultTableDbContext.BulkShardingEnumerable(list); - using (var tran = _defaultTableDbContext.BeginTransaction()) - { - foreach (var dataSourceMap in dbContexts) - { - foreach (var tailMap in dataSourceMap.Value) - { - tailMap.Key.BulkInsert(tailMap.Value.ToList()); - //tailMap.Key.BulkDelete(tailMap.Value.ToList()); - //tailMap.Key.BulkUpdate(tailMap.Value.ToList()); - } - } - _defaultTableDbContext.SaveChanges(); - tran.Commit(); - } - -``` ## 自动追踪 默认shardingcore不支持自动追踪,并且也不建议使用自动追踪,如果你有需要shardingcore也默认提供了自动追踪功能 有两点需要注意 @@ -651,6 +618,47 @@ ctor inject IShardingRouteManager shardingRouteManager tran.Commit(); } ``` + + +## 批量操作 + +批量操作将对应的dbcontext和数据进行分离由用户自己选择第三方框架比如[`Z.EntityFramework.Plus.EFCore`](https://github.com/zzzprojects/EntityFramework-Plus) 进行批量操作或者 [`EFCore.BulkExtensions`](https://github.com/borisdj/EFCore.BulkExtensions) ,支持一切三方批量框架 +```c# +var list = new List(); +///通过集合返回出对应的k-v归集通过事务开启 + var dbContexts = _defaultTableDbContext.BulkShardingEnumerable(list); + + + foreach (var dataSourceMap in dbContexts) + { + foreach (var tailMap in dataSourceMap.Value) + { + tailMap.Key.BulkInsert(tailMap.Value.ToList()); + //tailMap.Key.BulkDelete(tailMap.Value.ToList()); + //tailMap.Key.BulkUpdate(tailMap.Value.ToList()); + } + } + _defaultTableDbContext.SaveChanges(); + //or + var dbContexts = _defaultTableDbContext.BulkShardingEnumerable(list); + using (var tran = _defaultTableDbContext.BeginTransaction()) + { + foreach (var dataSourceMap in dbContexts) + { + foreach (var tailMap in dataSourceMap.Value) + { + tailMap.Key.BulkInsert(tailMap.Value.ToList()); + //tailMap.Key.BulkDelete(tailMap.Value.ToList()); + //tailMap.Key.BulkUpdate(tailMap.Value.ToList()); + } + } + _defaultTableDbContext.SaveChanges(); + tran.Commit(); + } + +``` +## code-first + ## 读写分离 该框架目前已经支持一主多从的读写分离`AddReadWriteSeparation`,支持轮询 Loop和随机 Random两种读写分离策略,又因为读写分离多链接的时候会导致数据读写不一致,(如分页其实是2步第一步获取count,第二部获取list)会导致数据量在最后几页出现缺量的问题, 针对这个问题框架目前实现了自定义读链接获取策略`ReadConnStringGetStrategyEnum.LatestEveryTime`表示为每次都是新的(这个情况下会出现上述问题),`ReadConnStringGetStrategyEnum.LatestFirstTime`表示以dbcontext作为单位获取一次(同dbcontext不会出现问题), diff --git a/samples/Sample.Migrations/DefaultDesignTimeDbContextFactory.cs b/samples/Sample.Migrations/DefaultDesignTimeDbContextFactory.cs index e5dc02e3..d7b2c787 100644 --- a/samples/Sample.Migrations/DefaultDesignTimeDbContextFactory.cs +++ b/samples/Sample.Migrations/DefaultDesignTimeDbContextFactory.cs @@ -22,8 +22,8 @@ namespace Sample.Migrations .ReplaceService>() ).Begin(o => { - o.CreateShardingTableOnStart = true; - o.EnsureCreatedWithOutShardingTable = true; + o.CreateShardingTableOnStart = false; + o.EnsureCreatedWithOutShardingTable = false; o.AutoTrackEntity = true; }) .AddShardingQuery((conStr, builder) => builder.UseSqlServer(conStr) @@ -45,8 +45,7 @@ namespace Sample.Migrations public DefaultShardingTableDbContext CreateDbContext(string[] args) { - var dbContextOptions = new DbContextOptionsBuilder().UseSqlServer("Data Source=localhost;Initial Catalog=ShardingCoreDBMigration;Integrated Security=True;").Options; - return new DefaultShardingTableDbContext(dbContextOptions); + return ShardingContainer.GetService(); } } } diff --git a/samples/Sample.Migrations/EFCores/ShardingWithMod.cs b/samples/Sample.Migrations/EFCores/ShardingWithMod.cs index bd2bc9b3..5df2d5c6 100644 --- a/samples/Sample.Migrations/EFCores/ShardingWithMod.cs +++ b/samples/Sample.Migrations/EFCores/ShardingWithMod.cs @@ -16,6 +16,9 @@ namespace Sample.Migrations.EFCores public string Id { get; set; } public string Name { get; set; } public int Age { get; set; } + public string TextStr { get; set; } + public string TextStr1 { get; set; } + public string TextStr2 { get; set; } } public class ShardingWithModMap : IEntityTypeConfiguration @@ -25,6 +28,10 @@ namespace Sample.Migrations.EFCores builder.HasKey(o => o.Id); builder.Property(o => o.Id).IsRequired().IsUnicode(false).HasMaxLength(128); builder.Property(o => o.Name).HasMaxLength(128); + builder.Property(o => o.Name).HasMaxLength(128); + builder.Property(o => o.TextStr).IsRequired().HasMaxLength(128).HasDefaultValue(""); + builder.Property(o => o.TextStr1).IsRequired().HasMaxLength(128).HasDefaultValue("123"); + builder.Property(o => o.TextStr2).IsRequired().HasMaxLength(128).HasDefaultValue("123"); builder.ToTable(nameof(ShardingWithMod)); } } diff --git a/samples/Sample.Migrations/Migrations/ShardingMigrations/20211007005204_EFCoreShardingAddTextStr.Designer.cs b/samples/Sample.Migrations/Migrations/ShardingMigrations/20211007005204_EFCoreShardingAddTextStr.Designer.cs new file mode 100644 index 00000000..477727f7 --- /dev/null +++ b/samples/Sample.Migrations/Migrations/ShardingMigrations/20211007005204_EFCoreShardingAddTextStr.Designer.cs @@ -0,0 +1,93 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Sample.Migrations.EFCores; + +namespace Sample.Migrations.Migrations.ShardingMigrations +{ + [DbContext(typeof(DefaultShardingTableDbContext))] + [Migration("20211007005204_EFCoreShardingAddTextStr")] + partial class EFCoreShardingAddTextStr + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("ProductVersion", "5.0.10") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("Sample.Migrations.EFCores.NoShardingTable", b => + { + b.Property("Id") + .HasMaxLength(128) + .IsUnicode(false) + .HasColumnType("varchar(128)"); + + b.Property("Age") + .HasColumnType("int"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.ToTable("NoShardingTable"); + }); + + modelBuilder.Entity("Sample.Migrations.EFCores.ShardingWithDateTime", b => + { + b.Property("Id") + .HasMaxLength(128) + .IsUnicode(false) + .HasColumnType("varchar(128)"); + + b.Property("Age") + .HasColumnType("int"); + + b.Property("CreateTime") + .HasColumnType("datetime2"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.ToTable("ShardingWithDateTime"); + }); + + modelBuilder.Entity("Sample.Migrations.EFCores.ShardingWithMod", b => + { + b.Property("Id") + .HasMaxLength(128) + .IsUnicode(false) + .HasColumnType("varchar(128)"); + + b.Property("Age") + .HasColumnType("int"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TextStr") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasDefaultValue(""); + + b.HasKey("Id"); + + b.ToTable("ShardingWithMod"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/samples/Sample.Migrations/Migrations/ShardingMigrations/20211007005204_EFCoreShardingAddTextStr.cs b/samples/Sample.Migrations/Migrations/ShardingMigrations/20211007005204_EFCoreShardingAddTextStr.cs new file mode 100644 index 00000000..9f5147ae --- /dev/null +++ b/samples/Sample.Migrations/Migrations/ShardingMigrations/20211007005204_EFCoreShardingAddTextStr.cs @@ -0,0 +1,25 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Sample.Migrations.Migrations.ShardingMigrations +{ + public partial class EFCoreShardingAddTextStr : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "TextStr", + table: "ShardingWithMod", + type: "nvarchar(128)", + maxLength: 128, + nullable: false, + defaultValue: ""); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "TextStr", + table: "ShardingWithMod"); + } + } +} diff --git a/samples/Sample.Migrations/Migrations/ShardingMigrations/20211007010210_EFCoreShardingAddTextStr1.Designer.cs b/samples/Sample.Migrations/Migrations/ShardingMigrations/20211007010210_EFCoreShardingAddTextStr1.Designer.cs new file mode 100644 index 00000000..798bb679 --- /dev/null +++ b/samples/Sample.Migrations/Migrations/ShardingMigrations/20211007010210_EFCoreShardingAddTextStr1.Designer.cs @@ -0,0 +1,100 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Sample.Migrations.EFCores; + +namespace Sample.Migrations.Migrations.ShardingMigrations +{ + [DbContext(typeof(DefaultShardingTableDbContext))] + [Migration("20211007010210_EFCoreShardingAddTextStr1")] + partial class EFCoreShardingAddTextStr1 + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("ProductVersion", "5.0.10") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("Sample.Migrations.EFCores.NoShardingTable", b => + { + b.Property("Id") + .HasMaxLength(128) + .IsUnicode(false) + .HasColumnType("varchar(128)"); + + b.Property("Age") + .HasColumnType("int"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.ToTable("NoShardingTable"); + }); + + modelBuilder.Entity("Sample.Migrations.EFCores.ShardingWithDateTime", b => + { + b.Property("Id") + .HasMaxLength(128) + .IsUnicode(false) + .HasColumnType("varchar(128)"); + + b.Property("Age") + .HasColumnType("int"); + + b.Property("CreateTime") + .HasColumnType("datetime2"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.ToTable("ShardingWithDateTime"); + }); + + modelBuilder.Entity("Sample.Migrations.EFCores.ShardingWithMod", b => + { + b.Property("Id") + .HasMaxLength(128) + .IsUnicode(false) + .HasColumnType("varchar(128)"); + + b.Property("Age") + .HasColumnType("int"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TextStr") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasDefaultValue(""); + + b.Property("TextStr1") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasDefaultValue("123"); + + b.HasKey("Id"); + + b.ToTable("ShardingWithMod"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/samples/Sample.Migrations/Migrations/ShardingMigrations/20211007010210_EFCoreShardingAddTextStr1.cs b/samples/Sample.Migrations/Migrations/ShardingMigrations/20211007010210_EFCoreShardingAddTextStr1.cs new file mode 100644 index 00000000..c87b5101 --- /dev/null +++ b/samples/Sample.Migrations/Migrations/ShardingMigrations/20211007010210_EFCoreShardingAddTextStr1.cs @@ -0,0 +1,25 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Sample.Migrations.Migrations.ShardingMigrations +{ + public partial class EFCoreShardingAddTextStr1 : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "TextStr1", + table: "ShardingWithMod", + type: "nvarchar(128)", + maxLength: 128, + nullable: false, + defaultValue: "123"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "TextStr1", + table: "ShardingWithMod"); + } + } +} diff --git a/samples/Sample.Migrations/Migrations/ShardingMigrations/20211007011252_EFCoreShardingAddTextStr2.Designer.cs b/samples/Sample.Migrations/Migrations/ShardingMigrations/20211007011252_EFCoreShardingAddTextStr2.Designer.cs new file mode 100644 index 00000000..4a81212f --- /dev/null +++ b/samples/Sample.Migrations/Migrations/ShardingMigrations/20211007011252_EFCoreShardingAddTextStr2.Designer.cs @@ -0,0 +1,107 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Sample.Migrations.EFCores; + +namespace Sample.Migrations.Migrations.ShardingMigrations +{ + [DbContext(typeof(DefaultShardingTableDbContext))] + [Migration("20211007011252_EFCoreShardingAddTextStr2")] + partial class EFCoreShardingAddTextStr2 + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("ProductVersion", "5.0.10") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("Sample.Migrations.EFCores.NoShardingTable", b => + { + b.Property("Id") + .HasMaxLength(128) + .IsUnicode(false) + .HasColumnType("varchar(128)"); + + b.Property("Age") + .HasColumnType("int"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.ToTable("NoShardingTable"); + }); + + modelBuilder.Entity("Sample.Migrations.EFCores.ShardingWithDateTime", b => + { + b.Property("Id") + .HasMaxLength(128) + .IsUnicode(false) + .HasColumnType("varchar(128)"); + + b.Property("Age") + .HasColumnType("int"); + + b.Property("CreateTime") + .HasColumnType("datetime2"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.ToTable("ShardingWithDateTime"); + }); + + modelBuilder.Entity("Sample.Migrations.EFCores.ShardingWithMod", b => + { + b.Property("Id") + .HasMaxLength(128) + .IsUnicode(false) + .HasColumnType("varchar(128)"); + + b.Property("Age") + .HasColumnType("int"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TextStr") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasDefaultValue(""); + + b.Property("TextStr1") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasDefaultValue("123"); + + b.Property("TextStr2") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasDefaultValue("123"); + + b.HasKey("Id"); + + b.ToTable("ShardingWithMod"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/samples/Sample.Migrations/Migrations/ShardingMigrations/20211007011252_EFCoreShardingAddTextStr2.cs b/samples/Sample.Migrations/Migrations/ShardingMigrations/20211007011252_EFCoreShardingAddTextStr2.cs new file mode 100644 index 00000000..9f01d39c --- /dev/null +++ b/samples/Sample.Migrations/Migrations/ShardingMigrations/20211007011252_EFCoreShardingAddTextStr2.cs @@ -0,0 +1,25 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Sample.Migrations.Migrations.ShardingMigrations +{ + public partial class EFCoreShardingAddTextStr2 : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "TextStr2", + table: "ShardingWithMod", + type: "nvarchar(128)", + maxLength: 128, + nullable: false, + defaultValue: "123"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "TextStr2", + table: "ShardingWithMod"); + } + } +} diff --git a/samples/Sample.Migrations/Migrations/ShardingMigrations/DefaultShardingTableDbContextModelSnapshot.cs b/samples/Sample.Migrations/Migrations/ShardingMigrations/DefaultShardingTableDbContextModelSnapshot.cs index c2a47a3e..1c969e9a 100644 --- a/samples/Sample.Migrations/Migrations/ShardingMigrations/DefaultShardingTableDbContextModelSnapshot.cs +++ b/samples/Sample.Migrations/Migrations/ShardingMigrations/DefaultShardingTableDbContextModelSnapshot.cs @@ -74,6 +74,27 @@ namespace Sample.Migrations.Migrations.ShardingMigrations .HasMaxLength(128) .HasColumnType("nvarchar(128)"); + b.Property("TextStr") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasDefaultValue(""); + + b.Property("TextStr1") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasDefaultValue("123"); + + b.Property("TextStr2") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasDefaultValue("123"); + b.HasKey("Id"); b.ToTable("ShardingWithMod"); diff --git a/samples/Sample.Migrations/readme.md b/samples/Sample.Migrations/readme.md new file mode 100644 index 00000000..b9850a6b --- /dev/null +++ b/samples/Sample.Migrations/readme.md @@ -0,0 +1,117 @@ +本项目迁移参考[efcore.sharding](https://github.com/Coldairarrow/EFCore.Sharding/tree/master/examples/Demo.DbMigrator) +## 迁移步骤 + + 1. 执行迁移命令,但不执行更新命令 + 2. 执行脚本命令,获得到Sql语句后,在开发环境的数据库中执行 + +#### 迁移数据库 + + 初始化:Add-Migration InitialCreate (Add-Migration EFCoreSharding -Context DefaultShardingTableDbContext -OutputDir Migrations\ShardingMigrations) + 迁移:Add-Migration [NewMigration] -Context CustomContext + 还原:Remove-Migration -Context CustomContext + 脚本:Script-Migration -Context CustomContext -from:[TargetMigration] ( Script-Migration -Context DefaultShardingTableDbContext)用于生产环境 + 更新:Update-Database -Context CustomContext (Update-Database -Context DefaultShardingTableDbContext -Verbose) + +## 迁移说明 + + Scaffold-DbContext 'Data Source=.;Initial Catalog=TesbDb;Integrated Security=True;Pooling=true;' -Schemas 'PDEV' -UseDatabaseNames -DataAnnotations -Force Microsoft.EntityFrameworkCore.SqlServer + +1、获取帮助信息 + + Get-Help about_EntityFrameworkCore + +2.1、一般的初始化数据库指令(将会创建新数据库): + + Add-Migration InitialCreate + + 效果:会在项目中生成类似 201708220135292_InitialCreate.cs 的类,里面包含了数据库的创建逻辑。 + +2.2、已存在数据库时的初始化指令(只生成__MigrationHistory表): + + Add-Migration InitialCreate –IgnoreChanges + + 效果:会在项目中生成类似 201708220135292_InitialCreate.cs 的类,里面不包含任何逻辑。 + +3、添加新的迁移 + + Add-Migration [NewMigration] + + 效果:会在项目中生成类似 201708220136184_AddSomething.cs 的类,里面包含了本次迁移的更改逻辑。 + 注意:AddSomething 的命名是唯一的,所以要注意妥善命名。 + +4、删除迁移 + + Remove-Migration + +5.1、更新数据库 + + Update-Database + + 效果:将未应用的迁移提交到数据库。 + +5.2、更新数据库(-Verbose) + + Update-Database -Verbose + + 效果:同时显示执行的SQL语句。 + +5.3、更新数据库(-TargetMigration) + + Update-Database -TargetMigration:AddSomething + + 效果:这个命令将会运行 AddSomething 之后的所有迁移的 Down 命令,从而将数据库还原到 AddSomething 的版本。 + 特别地:Update-Database –TargetMigration: $InitialDatabase 可以将数据库还原到最初始的版本。 + +6、得到SQL脚本(-Script),常用于将更改发布到生产环境 + + Script-Migration + 例子 获取从InitialCreate 到 AddInspectorWorkShift的变更的sql脚本 + Script-Migration -Context BusinessDbContext -from InitialCreate -to AddInspectorWorkShift + + 此命令有几个选项。 + from 迁移应是运行该脚本前应用到数据库的最后一个迁移。 如果未应用任何迁移,请指定 0(默认值)。 + to 迁移是运行该脚本后应用到数据库的最后一个迁移。 它默认为项目中的最后一个迁移。 + 可以选择生成 idempotent 脚本。 此脚本仅会应用尚未应用到数据库的迁移。 如果不确知应用到数据库的最后一个迁移或需要部署到多个可能分别处于不同迁移的数据库,此脚本非常有用。 + + +##注意点 +```c# +//创建对应的IDesignTimeDbContextFactory并且设置启动时不建表启动时不建库 `.ReplaceService>()` 添加自动分表迁移 + public class DefaultDesignTimeDbContextFactory: IDesignTimeDbContextFactory + { + static DefaultDesignTimeDbContextFactory() + { + var services = new ServiceCollection(); + services.AddShardingDbContext( + o => + o.UseSqlServer("Data Source=localhost;Initial Catalog=ShardingCoreDBMigration;Integrated Security=True;") + .ReplaceService>() + ).Begin(o => + { + o.CreateShardingTableOnStart = false; + o.EnsureCreatedWithOutShardingTable = false; + o.AutoTrackEntity = true; + }) + .AddShardingQuery((conStr, builder) => builder.UseSqlServer(conStr) + .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)) + .AddShardingTransaction((connection, builder) => + builder.UseSqlServer(connection)) + .AddDefaultDataSource("ds0", + "Data Source=localhost;Initial Catalog=ShardingCoreDBMigration;Integrated Security=True;") + .AddShardingTableRoute(o => + { + o.AddShardingTableRoute(); + o.AddShardingTableRoute(); + }).End(); + services.AddLogging(); + var buildServiceProvider = services.BuildServiceProvider(); + ShardingContainer.SetServices(buildServiceProvider); + new ShardingBootstrapper(buildServiceProvider).Start(); + } + + public DefaultShardingTableDbContext CreateDbContext(string[] args) + { + return ShardingContainer.GetService(); + } + } +``` \ No newline at end of file diff --git a/src/ShardingCore/Helpers/MigrationHelper.cs b/src/ShardingCore/Helpers/MigrationHelper.cs index e333d64c..bc7d861f 100644 --- a/src/ShardingCore/Helpers/MigrationHelper.cs +++ b/src/ShardingCore/Helpers/MigrationHelper.cs @@ -35,16 +35,20 @@ namespace ShardingCore.Helpers List addCmds ) where TShardingDContext:DbContext,IShardingDbContext { - + var migrationCommands = (List) builder.GetFieldValue("_commands"); addCmds.ForEach(aAddCmd => { var shardingCmds = BuildShardingCmds(operation, aAddCmd.CommandText, sqlGenerationHelper); - //针对builder的原始表进行移除 - shardingCmds.ForEach(aShardingCmd => + if (shardingCmds.IsNotEmpty()) { - builder.Append(aShardingCmd) - .EndCommand(); - }); + migrationCommands.Remove(aAddCmd); + //针对builder的原始表进行移除 + shardingCmds.ForEach(aShardingCmd => + { + builder.Append(aShardingCmd) + .EndCommand(); + }); + } }); } @@ -130,13 +134,15 @@ namespace ShardingCore.Helpers && x.PropertyType.GetGenericTypeDefinition() == typeof(List<>) && typeof(MigrationOperation).IsAssignableFrom(x.PropertyType.GetGenericArguments()[0]); //其它 - operation.GetType().GetProperties() + var propertyInfos = operation.GetType().GetProperties() .Where(x => x.Name != "Name" - && x.Name != "Table" - && x.PropertyType != typeof(object) - && (typeof(MigrationOperation).IsAssignableFrom(x.PropertyType) || listPropertyWhere(x)) - ) - .ToList() + && x.Name != "Table" + && x.PropertyType != typeof(object) + && (typeof(MigrationOperation).IsAssignableFrom(x.PropertyType) || listPropertyWhere(x)) + ) + .ToList(); + + propertyInfos .ForEach(aProperty => { var propertyValue = aProperty.GetValue(operation);