How to seed your database with EF Core - Day 21 - 24 days of "Front-end Development with ASP.NET Core, Angular, and Bootstrap"

Yesterday I've shown how to do EF Core DB migrations using either the Package Manager Console or the dotnet CLI. But you can also do these code migrations automatically, triggering them via code.

After following the steps shown yesterday, you have all your migrations setup, and you can apply the DB changes using the dotnet CLI. But there is less-know feature, still experimental and not ironed out completely, that makes it possible to run migrations from code, and even seeding the DB with initial data.

Apply migrations with code

To just apply migrations you need to call the db.Database.Migrate() method, where db is the EF Context.

Typically the following is the code needed to run the migration in code:

public static void Initialize(IServiceProvider service)
{
    using (var serviceScope = service.CreateScope())
    {
        var scopeServiceProvider = serviceScope.ServiceProvider;
        var db = scopeServiceProvider.GetService<TriathlonRaceTrackingContext>();
        db.Database.Migrate();
    }
}

This method can be called in the Configure method in the Startup class:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
  ...
  Initialize(app.ApplicationServices);
}

Seeding the DB with data

As part of the database initialization you can also add some initial test data to the database. Unfortunately it is not that automated as in Entity Framework 6, but can be coded manually.

For, example, to add a new entry in the Race table, to code is as following:

private static async Task InsertTestData(TriathlonRaceTrackingContext context)
{
    if(context.Races.Any())
        return;
    var race = new Race { Name="Ironman World Championship 2017",Location="Kona, Hawaii",Date=new DateTime(2017,10,14,7,0,0) };
    context.Add(race);
    await context.SaveChangesAsync();
}

The advantage of having to code it yourself is that you can decide if/when/how to seed the database. In this I just do it if the Race table is empty. But I could have decided to always wipe it clean, or anything else.

To include data seeding into the Initialize method, a few changes have to made as the data seeding is an async method. So the Initialize becomes an InitializeAsync:

public static async Task InitializeAsync(IServiceProvider service)
{
    using (var serviceScope = service.CreateScope())
    {
        var scopeServiceProvider = serviceScope.ServiceProvider;
        var db = scopeServiceProvider.GetService<TriathlonRaceTrackingContext>();
        db.Database.Migrate();
        await InsertTestData(db);
    }
}

Also the call from the Configure method must be slightly changed into InitializeAsync(app.ApplicationServices).Wait();.

This post is an extract of chapter 9 of my upcoming book "Front-end Development with ASP.NET Core, Angular, and Bootstrap". To know more about what I'm publishing, don't forget to check my blog again, subscribe to my RSS feed, follow me on twitter or like the Facebook page of my book.