Advanced Entity Framework Core: Extract data access layer with migrations to the library project and Execute migrations from the command line

Advanced Entity Framework Core Tips In Practice

Code that contains examples and many more can be found here.

Extract migrations to the library project

Typically when you learn how to do migrations, you will most likely see examples with a single project in the solution which is executable, like a console or web application. However, after that, you will face trouble when you split the application into different layers and put EF Core migrations to the library project, which is not executable.

So let's imagine you have a solution with many projects including a web application with the name "MiniService", which contains appsettings.json and a library project with DbContext and Migrations with any name f.e. "MiniService.Data". You most likely want to use the exact connection string in the appsettings.json used by the web app.

To get that working you need to use IDesignTimeDbContextFactory<AppContext>

Here is copy-paste example for you to accomplish this split easily,

Can be found here.

using System;
using System.IO;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;

namespace MiniService.Data.Persistence
{
    public class DbContextDesignFactory : IDesignTimeDbContextFactory<AppContext>
    {
        private const string connectionStringPath = "ConnectionStrings:DefaultConnection";
        private const string relativePathToConfig = @"..\MiniService\appsettings.json";

        public AppContext CreateDbContext(string[] args)
        {
            // dotnet ef database update -- FirstAppArg "second argument" ThirdAppArg
            // Console.WriteLine($"args: {string.Join("; ", args)}");

            var path = Path.GetFullPath($@"{Directory.GetCurrentDirectory()}\{relativePathToConfig}");

            Console.WriteLine($"Assessing: {path}");

            var configuration = new ConfigurationBuilder().AddJsonFile(path).Build();
            var connectionString = configuration[connectionStringPath];

            Console.WriteLine($"{connectionStringPath}: '{connectionString}'");

            var options = new DbContextOptionsBuilder<AppContext>();
            options.UseNpgsql(connectionString);
            //options.UseSqlServer(connectionString);

            return new AppContext(options.Options);
        }
    }
}

More info can be found here.

Running migrations from the command line

May be different cases when you will need to run migrations from the command line, for example, there is no 'Package Manager Console' in VS for Mac.

Let's imagine "MiniService.Data" is the name of the project with DB context and migrations.

Here is an instruction that can be placed in the ReadMe somewhere near the migrations to guide you each time:

# EF Core Migrations via command line and dotnet tool
No 'Package Manager Console' in VS for Mac

### Instruction:
1. Install EF Tools: "dotnet tool install --global dotnet-ef" (update: "dotnet tool update --global dotnet-ef")

2. Open Terminal at the MiniService.Data root directory

3. Create Migration: "dotnet ef migrations add {NEW_MIGRATION_NAME}"
    * [Optional] '-p MiniService.Data' use it if run not from the MiniService.Data project root
    * [Optional] '-c AppContext' if there is more than one context in the project
        
4. Execute migrations: "dotnet ef database update"
    * [Optional] '-p MiniService.Data'
    * [Optional] '-c AppContext'
        
5. Generate SQL: "dotnet ef migrations script {CURRENT_MIGRATION_NAME or 0 if new DB} {NEW_MIGRATION_NAME} -o ./Migrations/Scripts/{FILENAME}.sql"
    * [Optional] -c AppContext
    * Example: "dotnet ef migrations script 0 Init -o ./Migrations/Scripts/Init.sql"

### More commands:
- dotnet ef database drop
- dotnet ef migrations list
- dotnet ef migrations remove

### More info:
- https://www.entityframeworktutorial.net/efcore/cli-commands-for-ef-core-migration.aspx