How to add Entity Framework Core migrations  to own assembly
Tags: database, dotnet, csharp, efcore
Published: 2021-01-08 10:40:01


What we want to do is to store migrations in its own project/assembly for easier maintenance and to keep migration specific code out of the production binaries. We also do not want our startup project to depend on migration specific libraries. 

For this example I assume we already have a project in place
that could look something like this

> MyApp.Web.Api <-- ASP.Net Project
> MyApp.Application <-- Class Library
> MyApp.Domain <-- Class Library
> MyApp.Infrastructure <-- Class Library (contains DBContext)


## Create new migrations class library

We start by creating new class library to hold our migrations
called `MyApp.Infrastructure.Migrations`

```
dotnet new classlib -n MyApp.Persistence.Migrations
```

We add reference to Microsoft.EntityFrameworkCore and Microsoft.EntityFrameworkCore.Design. The later is needed for the tooling to be able to detect and generate migration scripts 

_From MyApp.Infrastructure.Migrations folder_
```
dotnet add package Microsoft.EntityFrameworkCore --version 5.0.1
dotnet add package Microsoft.EntityFrameworkCore.Design --version 5.0.1
```

## Add reference to project containing DBContext

The entity framework migrations tool need to find our DBContext that is located in different project so we need to reference our MyApp.Infrastructure project

_From MyApp.Infrastructure.Migrations folder_
```
dotnet add reference ../MyApp.Infrastructure/MyApp.Infrastructure.csproj
```

## Implement IDesignTimeDbContextFactory

To avoid need to use the startup project we need to implement IDesignTimeDbContextFactory so that migration tools can find the appropriate DBContext file. So we crate a new file called ApplicationDbContextFactory.cs with code below

_ApplicationDbContextFactory.cs_
``` c#
using System;
using System.IO;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;
using MyApp.Infrastructure;

namespace MyApp.Infrastructure.Migrations
{
    public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
    {
        public ApplicationDbContext CreateDbContext(string[] args)
        {
            var configuration = new ConfigurationBuilder()
                 .SetBasePath(Directory.GetCurrentDirectory())
                 .AddJsonFile("appsettings.json", true)
                 .AddEnvironmentVariables()
                 .Build();

            var builder = new DbContextOptionsBuilder();

            var connectionString = configuration
                        .GetConnectionString("DefaultConnection");

            builder.UseSqlServer(connectionString,
                        x => x.MigrationsAssembly(typeof(ApplicationDbContextFactory).Assembly.FullName));



            return new ApplicationDbContext(builder.Options);
        }
    }
}
```

We are letting the tool initialize our DBContext directly from our migrations library so we need to provide the connection string.
We do that by creating appsettings.json file inside our migrations class library

_appsettings.json_
``` json
{ 

    "ConnectionStrings": {
        "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=myapp;Trusted_Connection=True;MultipleActiveResultSets=true"
    }
}
```


## Add migrations
Now run the migrations add to create our migrations folder structure inside our new project

From MyApp.Infrastructure.Migrations folder
```
dotnet ef migrations add InitialCreate
```