基于非源码的EFCore数据库迁移

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会报错

image.png

代码的修改也很简单,增加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目录:


image.png

再执行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
image.png

执行成功后,我们去数据库查看一下,可以看到数据库和相应的表都创建完成。


image.png
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个了,表示数据库迁移成功。

image.png

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上下载。

你可能感兴趣的:(基于非源码的EFCore数据库迁移)