- 迁移基本步骤参考
dotnet ef migrations add {migration name} -p {dbcontext project} -s {host startup project}
- 这里的
migration name
,我以AddData
为例: - 发现
Migrations
文件夹下多了两个文件20180610024345_AddData.cs
和20180610024345_AddData.Designer.cs
- 这边我们只关注前一个文件,里面有一个类继承自
Migration
,它有两个函数Up
和Down
,且都是空的,熟悉ef的人对这两个函数的大体作用应该比较清楚 - 数据要初始化主要使用到
Up
函数的实参MigrationBuilder migrationBuilder
,查看源码,这个函数提供了很多有用的函数InsertData
UpdateData
等
- 这里的
废话不多说,直接上代码
public partial class AddData : Migration { protected override void Up(MigrationBuilder migrationBuilder) { extra(migrationBuilder); } private void extra(MigrationBuilder migrationBuilder) { migrationBuilder.InsertRole(new IdentityRole() { Id = "master_id", Name = "Master", NormalizedName = "Master" }); migrationBuilder.InsertRole(new IdentityRole() { Id = "admin_id", Name = "Administrator", NormalizedName = "Administrator" }); migrationBuilder.InsertRole(new IdentityRole() { Id = "vistor_id", Name = "Vistor", NormalizedName = "Vistor" }); var pwdHasher = new PasswordHasher<IdentityUser>(); var user = new IdentityUser("DaneSpirit") { Id = "dane_id", NormalizedUserName = "DaneSpirit", SecurityStamp = Guid.NewGuid().ToString() }; user.PasswordHash = pwdHasher.HashPassword(user, "danespirit"); migrationBuilder.InsertSimpleUser(user); user = new IdentityUser("TestUser") { Id = "testuser_id", NormalizedUserName = "TestUser", SecurityStamp = Guid.NewGuid().ToString() }; user.PasswordHash = pwdHasher.HashPassword(user, "test"); migrationBuilder.InsertSimpleUser(user); migrationBuilder.InsertUserRole(new IdentityUserRole<string>() { UserId = "dane_id", RoleId = "master_id" }); migrationBuilder.InsertUserRole(new IdentityUserRole<string>() { UserId = "testuser_id", RoleId = "vistor_id" }); } protected override void Down(MigrationBuilder migrationBuilder) { } }
我的项目使用了Asp.Net Core Identity,这里我对User、Role、UserRole作了一些基本的初始化,
InsertRole
InsertSimpleUser
InsertUserRole
是扩展方法namespace Microsoft.EntityFrameworkCore.Migrations { static class MigrationBuilderExtensions { public static OperationBuilder<InsertDataOperation> InsertRole(this MigrationBuilder builder, IdentityRole role) { var insertDataOperation = new InsertDataOperation() { Table = "aspnetroles", Schema = null, Columns = new[] { "id", "name", "NormalizedName", "concurrencystamp" }, Values = new object[,] { { role.Id, role.Name, role.NormalizedName, role.ConcurrencyStamp } } }; builder.Operations.Add(insertDataOperation); return new OperationBuilder<InsertDataOperation>(insertDataOperation); } public static OperationBuilder<InsertDataOperation> InsertSimpleUser(this MigrationBuilder builder, IdentityUser user) { var insertDataOperation = new InsertDataOperation() { Table = "aspnetusers", Schema = null, Columns = new[] { "id", "username", "NormalizedUserName", "passwordhash", "EmailConfirmed", "AccessFailedCount", "LockoutEnabled", "PhoneNumberConfirmed", "TwoFactorEnabled", "concurrencystamp", "SecurityStamp" }, Values = new object[,] { { user.Id, user.UserName, user.NormalizedUserName, user.PasswordHash, false, 0, false, false, false, user.ConcurrencyStamp, user.SecurityStamp } } }; builder.Operations.Add(insertDataOperation); return new OperationBuilder<InsertDataOperation>(insertDataOperation); } public static OperationBuilder<InsertDataOperation> InsertUserRole(this MigrationBuilder builder, IdentityUserRole<string> userRole) { var insertDataOperation = new InsertDataOperation() { Table = "aspnetuserroles", Schema = null, Columns = new[] { "userid", "roleid" }, Values = new object[1, 2] { { userRole.UserId, userRole.RoleId } } }; builder.Operations.Add(insertDataOperation); return new OperationBuilder<InsertDataOperation>(insertDataOperation); } } }
扩展方法的使用参考了
MigrationBuilder
的源码- 特别注意1:
User
Role
的查询索引都是Normalized*Name
,所以咱们的初始化中必须要填充这个字段,否则在后期验证过程中会出现找不到该用户的Exception - 特别注意2:
User
的PasswordHash
必须是要经过PasswordHasher.HashPassword
函数处理过的,否则也没法在运行时验证通过
dotnet ef database update -p {dbcontext project} -s {host startup project}
不出意外,迁移顺利进行- 这里说句题外话,迁移后数据库中会出现一个非自定义表
__efmigrationshistory
,它是迁移的历史记录,一般情况下,在4中迁移成功后,再次调用4中的命令是不会执行的,主要原因是4的迁移记录已经记录在数据库中,不会发生二次迁移。如果要使4中的命令再次可执行,一个简单的方法是在数据库中将最新的一条迁移历史记录删除。