17

Is it possible to run an ef migration from DLL containing migrations and dbcontext? I'd like to run dotnet ef database update against my build artefacts without need of project.json and source codes.

In other words I'm looking for an equivalent of migrate.exe https://msdn.microsoft.com/en-us/data/jj618307.aspx from EF6

krlm
  • 817
  • 7
  • 18
  • Did you try and get any errors? – Haitham Shaddad Oct 17 '16 at 10:56
  • @HaithamShaddad: yes, `No executable found matching command "dotnet-ef"` but it's expected when you don't have project.json, I guess. – krlm Oct 17 '16 at 11:39
  • Yes, dotnet ef needs to be running inside the project directory with the presence of project.json, but why do you need to run it from a dll? it means your code is published and it should use automatic migration or you should have a backup from the DB – Haitham Shaddad Oct 17 '16 at 11:57
  • 3
    @HaithamShaddad: Continuous integration pipeline. I don't have sources at stage where I'd like to run DB migrations. Before I deploy them I'd like to update database and deploy only when it succeeds. With EF6 and `migrate.exe` I was able to create such pipeline. – krlm Oct 17 '16 at 12:06
  • I have wrote a very detailed answer about the possibilities [here](https://stackoverflow.com/questions/37562122/is-there-a-way-to-run-ef-core-rc2-tools-from-published-dll/59269689#59269689) – Major Dec 22 '19 at 10:29

4 Answers4

14

My team colleague found a way which allows you to run migrations on build artefacts without sources. Following command replace migrate.exe for us:

dotnet exec 
  --runtimeconfig ./HOST.runtimeconfig.json 
  --depsfile ./HOST.deps.json Microsoft.EntityFrameworkCore.Design.dll
  --assembly ./DB_CONTEXT_DLL.dll 
  --startup-assembly ./HOST.dll --data-dir ./ 
  --root-namespace DB_CONTEXT_NAMESPACE 
  --verbose database update --context DB_CONTEXT_CLASS -e development 

Update for 2.1.x version:

dotnet exec 
   --runtimeconfig ./HOST.runtimeconfig.json 
   --depsfile ./HOST.deps.json /PATH/TO/microsoft.entityframeworkcore.tools/.../ef.dll 
   --verbose database update --context DB_CONTEXT_CLASS
   --assembly ./DB_CONTEXT_DLL.dll 
   --startup-assembly ./HOST.dll --data-dir ./
krlm
  • 817
  • 7
  • 18
  • Hi,I tried this approach but I get the following error Unhandled Exception: System.MissingMethodException: Entry point not found in assembly 'Microsoft.EntityFrameworkCore.Des ign, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. Which version you had for this above solution? – Abi P Jun 15 '17 at 16:50
  • Here is the command dotnet exec --runtimeconfig ./Dummy.WebAPI.runtimeconfig.json --depsfile ./Dummy.WebAPI.deps.json Microsoft.EntityFrameworkCore.Design.dll --assembly ./Dummy.Data.dll --startup-assembly ./Dummy.WebAPI.dll --data-dir ./ --root-namespace Dummy.Data --verbose database update --context DummyContext -e development – Abi P Jun 15 '17 at 16:53
  • I'm currently using v1.1.2 of EF and here's CLI which works for us: `dotnet exec --runtimeconfig ./HOST.runtimeconfig.json --depsfile ./AboveCloud.WebApi.deps.json ef.dll --verbose database update --context DB_CONTEXT_CLASS -e production --assembly DB_CONTEXT_DLL ` but we also make a copy of this package: `cp /root/.nuget/packages/microsoft.entityframeworkcore.tools.dotnet/1.0.0/tools/netcoreapp1.0/ef.dll bin/Release/netcoreapp1.1/publish` – krlm Jun 16 '17 at 12:13
  • We don't hard code connection strings in classes. So, which one of these parameters is telling dotnet exec the connection information to the database server? Where's that connection (aka connection string) information stored? Is it in the .json flie? – Steve Kennedy May 18 '18 at 22:21
  • @SteveKennedy I had an implementation of `IDbContextFactory` which was reading settings from .json config file via `ConfigurationBuilder` – krlm May 28 '18 at 13:32
  • 2.1.3 didn't like it. The following worked for me: `dotnet exec --runtimeconfig ./HOST.runtimeconfig.json --depsfile ./HOST.deps.json %homepath%\.nuget\packages\microsoft.entityframeworkcore.tools\2.1.3\tools\netcoreapp2.0\any\ef.dll --verbose database update --context DB_CONTEXT_NAMESPACE.DB_CONTEXT_CLASS --assembly DB_CONTEXT.dll` This was obtained via both the answer and the comments. Note I had to change to `ef.dll` in `tools` and NOT `design`, in addition to removing the environment argument. – McAden Oct 10 '18 at 14:57
  • Had to revisit this. For anybody else in the future pay attention to the last 2 parameters of the "Updated for 2.1" portion of the answer above. Without those it wouldn't pull in my environment-specific appsettigs. – McAden Dec 03 '18 at 19:11
  • Had to revisit this. For anybody else in the future pay attention to the last 2 parameters of the "Updated for 2.1" portion of the answer above. Without those it wouldn't pull in my environment-specific appsettigs. – McAden Dec 03 '18 at 19:11
  • 1
    Still works with .NET 5. Can also specify connection string `--verbose database update --context ApplicationDbContext --connection "Server=srv;Database=db;User Id=user;Password=pswd;"` or make script file `--verbose migrations script --context ApplicationDbContext --idempotent --output migrations.sql` – JuztBe Jul 27 '21 at 10:09
9

Seems not possible run dotnet ef database update only with the DLL, and if you use the docker, the actual version of runtime microsoft/dotnet:1.1.0-preview1-runtime do not have the sdk installed (with the dotnet ef database update command).

One option to update database without use dotnet ef database update is execute the command bellow in some default action or startup routine.

_dbContext.Database.Migrate();
Ricardo Fontana
  • 4,583
  • 1
  • 21
  • 32
  • Hi, I am finally taking this approach and it is working. Thanks. – Abi P Jun 15 '17 at 21:33
  • This doesn't seem to work @AbiP What did you do to allow this? – Demodave Mar 19 '19 at 12:59
  • Sorry I could not understand your questions. but here is what I did. I called the context.Database.Migrate() from inside of the ConfigureServices method. Dont have the code handy right now to paste it. Let me know if this helps. – Abi P Mar 19 '19 at 17:53
  • @AbiP Sorry, I don't follow this where is ConfigureServices? – Demodave Mar 21 '19 at 12:41
  • I am assuming you are working on dotnet core. In the startup.cs class you should find a configureService method. I am referring to this method.string – Abi P Mar 21 '19 at 13:01
  • string sqlConnectionString = ConfigurationManager.Configuration.GetConnectionString("ConnectionString"); services.AddDbContext(opt => opt.UseSqlServer(sqlConnectionString, b => b.MigrationsAssembly("Assemblycontainign EF Core"))).AddScoped(typeof(DbContext), typeof(ContextClassName)); var optionsBuilder = new DbContextOptionsBuilder(); optionsBuilder.UseSqlServer(sqlConnectionString); using (var context = new ContextClassName(optionsBuilder.Options)) {context.Database.Migrate();} – Abi P Mar 21 '19 at 13:05
  • Read more about applying migrations at runtime here: https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/applying?tabs=dotnet-core-cli#apply-migrations-at-runtime – Adam Jonsson Oct 03 '22 at 11:33
0

I happen to use a factory to obtain a context, so based on Richardo's answer created a class like this. I use it as a singleton and call its ApplyMigrations method at service startup.

using System;
using Microsoft.EntityFrameworkCore;

namespace Nhs.Digital.Cwt.MultiStreamPublisher
{
    public class MigrationApplier
    {
        private IMyContextFactory _contextFactory;

        public MigrationApplier(IMyContextFactory contextFactory)
        {
            _contextFactory = contextFactory ?? throw new ArgumentNullException($"{nameof(contextFactory)} was null");
        }

        public void ApplyMigrations()
        {
            if (_contextFactory != null)
            {
                using (var context = _contextFactory.Create())
                {
                    _contextFactory = null;
                    context.Database.Migrate();
                }
            }
        }
    }
}

Damn ran into problems though as my deployment scripts expected the DB to be there so that DB permissions can be added to it. So it looks like I'll have to write a small console app just for the deploy script to use to make the DB ahead of adding DB permissions. Code on through the pain.

andrew pate
  • 3,833
  • 36
  • 28
0

I just created a small utility to solve this problem. It will works with any providers out of the box. The only requirements is your assembly must have a public implementation of IDesignTimeDbContextFactory.

The usage is very simple, just execute the src/EFMigrate project with the first argument is a path to your published assembly.

UltimaWeapon
  • 2,343
  • 18
  • 19