[Updated 4/27/2018 — Added an EF Core 2 version of this script in a new blog post.]
[Updated 3/29/2017 — Added a bash version of this script for deploying EF Core Migrations from Linux.]
Entity Framework Migrations let you deploy incremental updates to a target database. With Entity Framework Core (EF Core) this is done from the command line by going to the directory that contains your Entity Framework entity and migration code, compiling that code (dotnet build), and then calling “dotnet ef database update” to publish those changes to your target database.
This works great from a developer workstation or from a build server but it breaks down in the DevOps scenario where you want to deploy code that has already been built. Put another way, you can easily do an EF Core migration deploy if you have the source code — but if you only have the compiled assemblies (DLLs), you’re mostly out of luck.
I ran into this one while trying to deploy a build using a TFS Release Management (RM) pipeline. In RM, you take the output of a previous build, apply any configuration updates you need for your target environment, and then deploy the already built code into that environment. This typically involves deploying not just the code but also any database updates. And since you’re definitely NOT re-compiling that code — you’re deploying the already built DLLs — you slam face-first into this EF Core migration limitation.
The Solution
Based on a hint from Brice Lambson, I created a simple batch script (and bash shell script) that replicates what the “dotnet ef database update” command does under the surface. This takes the published output of your EF Core project, wires up the arguments for the source files, and triggers the database update logic.
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.dotnet\1.0.0\tools\netcoreapp1.0\ef.dll dotnet exec --depsfile .\%EfMigrationsDllDepsJson% --additionalprobingpath %PathToNuGetPackages% %PathToEfDll% database update --assembly .\%EfMigrationsDllName% --startup-assembly .\%EfMigrationsDllName% --project-dir . --content-root %DllDir% --data-dir %DllDir% --verbose --root-namespace %EfMigrationsNamespace%
The script assumes that it’s in the same directory as your published EF Core DLL. When I say “published”, I mean that you’ve run “dotnet publish -o {path}” on your EF Core project to compile it and publish just the source files for that project. So, copy the batch script into that published directory and then run the following command:
deploy-ef-migrations.bat {EfCoreRootNamespace}
The only arg that you need to supply for the Windows version is the root namespace for your EF Core code. By default, this is the same name as the DLL minus the “.dll” extension. For example, if my DLL is Benday.EfCore.Api.dll, then my call is
deploy-ef-migrations.bat Benday.EfCore.Api
For Linux, it’s the same except for the name of the script. For example, if my DLL is Benday.EfCore.Api.dll, then my call is
./deploy-ef-migrations.sh Benday.EfCore.Api
Summary
My recommendation is that, if you’re doing EF Core migrations as part of a TFS Release Management pipeline, you should do a separate “dotnet publish” for your EF Core API project to a location in your drop directory and then copy deploy-ef-migrations.bat into that drop directory folder. This will make deploying your migrations a lot easier to script out when you’re doing your RM release.
Here’s a link to that EF Core migration publish script for Windows. Here’s a link to the EF Core migration publish Linux bash script.
I hope this helps.
-Ben
— Looking for help getting your Entity Framework code plugged into your DevOps pipelines? Need some assistance scripting your DevOps deploys for your applications? Have you hit the wall on Entity Framework migrations and want to switch to SQL Server Data Tools projects? We can help. Drop us a line at info@benday.com.
Leave a Reply