添加并且优化修复efcore的code first添加readme

This commit is contained in:
xuejiaming 2021-10-07 10:00:59 +08:00
parent ce56d61e7f
commit d02fb72603
12 changed files with 585 additions and 52 deletions

View File

@ -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<SysUserMod>();
///通过集合返回出对应的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<SysUserMod>();
///通过集合返回出对应的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不会出现问题),

View File

@ -22,8 +22,8 @@ namespace Sample.Migrations
.ReplaceService<IMigrationsSqlGenerator, ShardingSqlServerMigrationsSqlGenerator<DefaultShardingTableDbContext>>()
).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<DefaultShardingTableDbContext>().UseSqlServer("Data Source=localhost;Initial Catalog=ShardingCoreDBMigration;Integrated Security=True;").Options;
return new DefaultShardingTableDbContext(dbContextOptions);
return ShardingContainer.GetService<DefaultShardingTableDbContext>();
}
}
}

View File

@ -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<ShardingWithMod>
@ -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));
}
}

View File

@ -0,0 +1,93 @@
// <auto-generated />
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<string>("Id")
.HasMaxLength(128)
.IsUnicode(false)
.HasColumnType("varchar(128)");
b.Property<int>("Age")
.HasColumnType("int");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.HasKey("Id");
b.ToTable("NoShardingTable");
});
modelBuilder.Entity("Sample.Migrations.EFCores.ShardingWithDateTime", b =>
{
b.Property<string>("Id")
.HasMaxLength(128)
.IsUnicode(false)
.HasColumnType("varchar(128)");
b.Property<int>("Age")
.HasColumnType("int");
b.Property<DateTime>("CreateTime")
.HasColumnType("datetime2");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.HasKey("Id");
b.ToTable("ShardingWithDateTime");
});
modelBuilder.Entity("Sample.Migrations.EFCores.ShardingWithMod", b =>
{
b.Property<string>("Id")
.HasMaxLength(128)
.IsUnicode(false)
.HasColumnType("varchar(128)");
b.Property<int>("Age")
.HasColumnType("int");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<string>("TextStr")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)")
.HasDefaultValue("");
b.HasKey("Id");
b.ToTable("ShardingWithMod");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -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<string>(
name: "TextStr",
table: "ShardingWithMod",
type: "nvarchar(128)",
maxLength: 128,
nullable: false,
defaultValue: "");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "TextStr",
table: "ShardingWithMod");
}
}
}

View File

@ -0,0 +1,100 @@
// <auto-generated />
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<string>("Id")
.HasMaxLength(128)
.IsUnicode(false)
.HasColumnType("varchar(128)");
b.Property<int>("Age")
.HasColumnType("int");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.HasKey("Id");
b.ToTable("NoShardingTable");
});
modelBuilder.Entity("Sample.Migrations.EFCores.ShardingWithDateTime", b =>
{
b.Property<string>("Id")
.HasMaxLength(128)
.IsUnicode(false)
.HasColumnType("varchar(128)");
b.Property<int>("Age")
.HasColumnType("int");
b.Property<DateTime>("CreateTime")
.HasColumnType("datetime2");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.HasKey("Id");
b.ToTable("ShardingWithDateTime");
});
modelBuilder.Entity("Sample.Migrations.EFCores.ShardingWithMod", b =>
{
b.Property<string>("Id")
.HasMaxLength(128)
.IsUnicode(false)
.HasColumnType("varchar(128)");
b.Property<int>("Age")
.HasColumnType("int");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<string>("TextStr")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)")
.HasDefaultValue("");
b.Property<string>("TextStr1")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)")
.HasDefaultValue("123");
b.HasKey("Id");
b.ToTable("ShardingWithMod");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -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<string>(
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");
}
}
}

View File

@ -0,0 +1,107 @@
// <auto-generated />
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<string>("Id")
.HasMaxLength(128)
.IsUnicode(false)
.HasColumnType("varchar(128)");
b.Property<int>("Age")
.HasColumnType("int");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.HasKey("Id");
b.ToTable("NoShardingTable");
});
modelBuilder.Entity("Sample.Migrations.EFCores.ShardingWithDateTime", b =>
{
b.Property<string>("Id")
.HasMaxLength(128)
.IsUnicode(false)
.HasColumnType("varchar(128)");
b.Property<int>("Age")
.HasColumnType("int");
b.Property<DateTime>("CreateTime")
.HasColumnType("datetime2");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.HasKey("Id");
b.ToTable("ShardingWithDateTime");
});
modelBuilder.Entity("Sample.Migrations.EFCores.ShardingWithMod", b =>
{
b.Property<string>("Id")
.HasMaxLength(128)
.IsUnicode(false)
.HasColumnType("varchar(128)");
b.Property<int>("Age")
.HasColumnType("int");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<string>("TextStr")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)")
.HasDefaultValue("");
b.Property<string>("TextStr1")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)")
.HasDefaultValue("123");
b.Property<string>("TextStr2")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)")
.HasDefaultValue("123");
b.HasKey("Id");
b.ToTable("ShardingWithMod");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -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<string>(
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");
}
}
}

View File

@ -74,6 +74,27 @@ namespace Sample.Migrations.Migrations.ShardingMigrations
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<string>("TextStr")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)")
.HasDefaultValue("");
b.Property<string>("TextStr1")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)")
.HasDefaultValue("123");
b.Property<string>("TextStr2")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)")
.HasDefaultValue("123");
b.HasKey("Id");
b.ToTable("ShardingWithMod");

View File

@ -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<IMigrationsSqlGenerator, ShardingSqlServerMigrationsSqlGenerator<DefaultShardingTableDbContext>>()` 添加自动分表迁移
public class DefaultDesignTimeDbContextFactory: IDesignTimeDbContextFactory<DefaultShardingTableDbContext>
{
static DefaultDesignTimeDbContextFactory()
{
var services = new ServiceCollection();
services.AddShardingDbContext<DefaultShardingTableDbContext, DefaultTableDbContext>(
o =>
o.UseSqlServer("Data Source=localhost;Initial Catalog=ShardingCoreDBMigration;Integrated Security=True;")
.ReplaceService<IMigrationsSqlGenerator, ShardingSqlServerMigrationsSqlGenerator<DefaultShardingTableDbContext>>()
).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<ShardingWithModVirtualTableRoute>();
o.AddShardingTableRoute<ShardingWithDateTimeVirtualTableRoute>();
}).End();
services.AddLogging();
var buildServiceProvider = services.BuildServiceProvider();
ShardingContainer.SetServices(buildServiceProvider);
new ShardingBootstrapper(buildServiceProvider).Start();
}
public DefaultShardingTableDbContext CreateDbContext(string[] args)
{
return ShardingContainer.GetService<DefaultShardingTableDbContext>();
}
}
```

View File

@ -35,16 +35,20 @@ namespace ShardingCore.Helpers
List<MigrationCommand> addCmds
) where TShardingDContext:DbContext,IShardingDbContext
{
var migrationCommands = (List<MigrationCommand>) builder.GetFieldValue("_commands");
addCmds.ForEach(aAddCmd =>
{
var shardingCmds = BuildShardingCmds<TShardingDContext>(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);