EFCore不再像EF6.x那样支持代码级别的完全自动的数据库迁移。不过EFCore提供了很方便的通过命令的方式来实现数据库的模型同步。
迁移方式主要是二种,基于Visual Studio带的包管理器的控制台和基于命令行的dotnet ef命令。前提是执行命令都需要有项目的源码,这个是有弊端的,我们一般开发项目发布到生产环境,开发者不允许直接访问,我们也不应该把源码发布到生产环境。
本文主要尝试只有dotnet publish发布的dll的基础下实现数据库的迁移。
1. 创建一个ASP Net Core的测试项目
我这里用的是Visual Studio 2017,创建一个Web API项目,连接本地的MySQL数据库。需要添加几个Nuget 包
还有一个是需要右键项目编辑csproj文件,然后添加一个DotNetCliToolReference
,否则执行dotnet ef会报错
代码的修改也很简单,增加2个类User和DataContext:
public class DataContext : DbContext
{
public DataContext(DbContextOptions options)
: base(options)
{
}
public DbSet User { get; set; }
}
public class User
{
public string Id { get; set; }
public string Name { get; set; }
//一开始先注释调Age这个属性,用于测试模型变化后的数据库迁移
//public string Age { get; set; }
}
在Startup里添加数据库连接的代码:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
var connection = "Server=localhost;Port=3306;Database=TestMySql; User=root;Password=123456;Charset=utf8";
services.AddDbContextPool(options => options.UseMySql(connection));
}
2. 定义初始化迁移
这个操作还是在源码目录下执行的,这个操作是定义数据库模型初始化迁移文件的,不能脱离源码。
D:\MigrationsSample\MigrationsSample> dotnet ef migrations add InitialCreate
Done. To undo this action, use 'ef migrations remove'
执行后,在源码目录会创建一个Mirgrations目录:
再执行dotnet publish命令:
PS D:\work\temp\MigrationsSample\MigrationsSample> dotnet publish
用于 .NET Core 的 Microsoft (R) 生成引擎版本 15.5.180.51428
版权所有(C) Microsoft Corporation。保留所有权利。
Restore completed in 94.18 ms for D:\MigrationsSample\MigrationsSample\MigrationsSample.csproj.
Restore completed in 113.93 ms for D:\MigrationsSample\MigrationsSample\MigrationsSample.csproj.
Restore completed in 126.06 ms for D:\MigrationsSample\MigrationsSample\MigrationsSample.csproj.
MigrationsSample -> D:\MigrationsSample\MigrationsSample\bin\Debug\netcoreapp2.0\MigrationsSample.dll
MigrationsSample -> D:\MigrationsSample\MigrationsSample\bin\Debug\netcoreapp2.0\publish\
3. 迁移应用到数据库
接下来我们把publish的目录所有文件拷贝到另外一个目录d:\temp\publish
,模拟一次发布过程。
我们需要在这个目录下执行数据库迁移。
需要额外在这个目录下创建一个bat文件,内容如下:
set EfMigrationsNamespace=%1
set EfMigrationsDllName=%1.dll
set EfMigrationsDllDepsJson=%1.deps.json
set DllDir=%cd%
set PathToNuGetPackages=%USERPROFILE%\.nuget\packages
set PathToEfDll=%PathToNuGetPackages%\microsoft.entityframeworkcore.tools\2.0.0\tools\netcoreapp2.0\ef.dll
dotnet exec --depsfile .\%EfMigrationsDllDepsJson% --additionalprobingpath %PathToNuGetPackages% %PathToEfDll% database update --assembly .\%EfMigrationsDllName% --startup-assembly .\%EfMigrationsDllName% --data-dir %DllDir% --verbose --root-namespace %EfMigrationsNamespace%
执行这个bat+dll的文件名
./databaseupdate MigrationsSample
执行成功后,我们去数据库查看一下,可以看到数据库和相应的表都创建完成。
4. 修改表模型后再次尝试数据库迁移
上个步骤后,数据库里的user表有2个字段,接下来我们修改一下User.cs,放开注释,相当于增加了一个字段Age
:
public class User
{
public string Id { get; set; }
public string Name { get; set; }
//一开始先注释调Age这个属性,用于测试模型变化后的数据库迁移
public string Age { get; set; }
}
然后再执行定义迁移和publish
注意这里迁移的名称要变了,不能再叫InitialCreate,我这里叫update1
D:\MigrationsSample\MigrationsSample> dotnet ef migrations add update1
Done. To undo this action, use 'ef migrations remove'
PS D:\MigrationsSample\MigrationsSample> dotnet publish
用于 .NET Core 的 Microsoft (R) 生成引擎版本 15.5.180.51428
版权所有(C) Microsoft Corporation。保留所有权利。
Restore completed in 87.98 ms for D:\MigrationsSample\MigrationsSample\MigrationsSample.csproj.
Restore completed in 116.2 ms for D:\MigrationsSample\MigrationsSample\MigrationsSample.csproj.
Restore completed in 126.37 ms for D:\MigrationsSample\MigrationsSample\MigrationsSample.csproj.
MigrationsSample -> D:\MigrationsSample\MigrationsSample\bin\Debug\netcoreapp2.0\MigrationsSample.dll
MigrationsSample -> D:\MigrationsSample\MigrationsSample\bin\Debug\netcoreapp2.0\publish\
再次发布到d:\temp\publish
目录,在这个目录下再次执行bat文件,执行完我们去查看数据库,发现user表的字段变成3个了,表示数据库迁移成功。
4.分析和总结
实现基于dll的数据库迁移核心就是那个bat文件,这个文件的来源是参考这里 。
实际上,你可以在dotnet ef database update后增加一个-v参数就可以发现这个命令分2个部分,第一步部分是build,第二个部分就说类似那个bat文件里的dotnet exec:
PS D:\MigrationsSample\MigrationsSample> dotnet ef database update -v
......
dotnet msbuild /target:GetEFProjectMetadata /property:EFProjectMetadataFile=C:\Users\liuyin\AppData\Local\Temp\tmp71D2.tmp /verbosity:quiet /nologo D:\MigrationsSample\MigrationsSample\MigrationsSample.csproj
dotnet build D:\MigrationsSample\MigrationsSample\MigrationsSample.csproj /verbosity:quiet /nologo
已成功生成。
0 个警告
0 个错误
已用时间 00:00:04.76
dotnet exec --depsfile D:\MigrationsSample\MigrationsSample\bin\Debug\netcoreapp2.0\MigrationsSample.deps.json --additionalprobingpath C:\Users\liuyin\.nuget\packages --additionalprobingpath "C:\Program Files\dotnet\sdk\NuGetFallbackFolder" --runtimeconfig D:\MigrationsSample\MigrationsSample\bin\Debug\netcoreapp2.0\MigrationsSample.runtimeconfig.json "C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.entityframeworkcore.tools.dotnet\2.0.1\tools\netcoreapp2.0\ef.dll" database update --assembly D:\MigrationsSample\MigrationsSample\bin\Debug\netcoreapp2.0\MigrationsSample.dll --startup-assembly D:\MigrationsSample\MigrationsSample\bin\Debug\netcoreapp2.0\MigrationsSample.dll --project-dir D:\MigrationsSample\MigrationsSample\ --verbose --root-namespace MigrationsSample
Using assembly 'MigrationsSample'.
Using startup assembly 'MigrationsSample'.
......
最后再提醒一下,如果是基于协同的开发,那个自动生成的Mirgrations目录最后和源码一起提交到源码管理服务器上,确保不会删除和遗漏。
所有源码可以从git上下载。