Dec 13

Recently I’ve been playing around with Entity Framework Core and it’s been a great positive experience overall, however as I started to port one of my projects over I fell foul of the lack of Seeding support. For those that haven’t used the Seed functionality in EF 6, it’s basically a method to populate the database with data that is invoked when migrations finish. There is a open GitHub issue regarding seeding support in EF Core.

My requirements are simple I’d like to use the dotnet CLI to run environment specific Migrations and Seeding from my continuous deployment pipeline. In this post I’m going to show you how I got environment specific Migrations and Seeding working. There are a couple of things that work differently that we need to workaround but that’s fine.

  • The first problem to solve is the lack of seeding support, this is easily solved and not an issue at all. You can use a empty migration and seed the data in the migration, this is a great because the seed is ran once if I need to update the data I create a new migration. We also benefit from being able to roll back any seed migrations.

  • The second problem I came across is that targeting class library projects for the update-database command is not supported. No problem I created a console app and problem solved.

  • The third problem to solve is how to get the environment switch from ef database update. This is what took a little bit of work – it turns out that currently EF Core tools are geared around a ASP.NET project hence not supporting targeting class library projects, running migrations on web start isn’t something I wanted to do for my production apps.

Reviewing the EF Core environment feature commit (which is one of the benefits of open source) confirmed that EF tools are looking for a Startup class and the switch is set via the injected IHostingEnvironment. This is now a problem because DI isn’t supported anymore for console apps.

My first attempt was to pull the EnvironmentName directly from the environment variable turns out this won’t work as it is only set for the current cmd session. It was feeling like I was hitting friction so I changed direction and tried using WebHostBuilder instead, and bingo it worked, it turns out that you can have a Startup class and call Build() but you don’t have to call Run() so you don’t end up running Kestrel by mistake.

Below is a gist of the working solution with some commentary:

Here I’m just bootstrapping our Startup class but notice I’m not calling Run().

In the Startup ctor I take IHostingEnvironment and set it to a private variable, then when ConfigureServices is called I set a Environment Variable for future use. Note that if “Development” is passed as the environment we default to “local”, this is because “Development” is the default and I wanted to avoid using the default in CD.

DbContext changes are quite simple if a database connectionstring is passed via OnConfiguring then we return. Otherwise if no connectionstring is passed we set up the config using the environment variable we set in startup, it’s this code that will be called during a migration.

Here is an example migration notice that DalSoftDbContext parameterless ctor is called allowing OnConfiguring (as described above) to use the environment config that was set using the environment variable.

Here is my project.json for reference but nothing special going on here.

Now all my migrations using the dotnet CLI use the correct appsettings for example for appsettings.production.json:


dotnet ef --project ../DalSoft.Data --startup-project ../DalSoft.Data database update --environment production

6 Responses to “Entity Framework Core Seeding Using Migrations”

  1. Steven McVicar says:

    Hi, thanks for this post! It’s very useful. Our team are currenlty debating whether to use EF Core or EF 6. EF Core is our preferred choice. However there are a number of issues with the latest release which are making us nervous. Your solutions above will help us a great deal.

    I’m curious to know though… Can you get migrations to run using dotnet CLI commands from within Visual Studio Team Services? If so can you let me know how you achieved this please?

    Cheers
    Steve

    • DalSoft says:

      @steven I do exactly this myself use:

      dotnet ef –project ../DalSoft.Data –startup-project ../DalSoft.Data database update –environment production

      Replace with your project name.

  2. Alfredo says:

    I want to seed different data in each environment. I don’t believe your solution can achieve this.

    • DalSoft says:

      Hi Alfredo, this is exactly what it does! Just change the –environment switch to your environment.

      The –environment switch isn’t available after EF Core 2.0, but it has just changed to use the ASPNETCORE_ENVIRONMENT environment setting instead.

      So in your seed code just check the value of the ASPNETCORE_ENVIRONMENT environment setting, and do the seed you want to do for that environment.

  3. This article contains very useful information on Entity Framework Core Seeding Using Migrations. Thanks for sharing this article.

  4. bernyLed says:

    EF Core uses this table to track all the applied migrations. So, this means that if we create another migration in our code and apply it, EF Core will apply only the newly created migration. But how does EF Core know what migration needs to be applied?

Leave a Reply

preload preload preload