Data Seeding Made Easier in ASP.NET Core & EF Core


On this post, we are going to setup the data seeder in ASP.NET Core App. We will also set the app to automatically run the data seeder and migration upon the start of the application via Program.cs

Mar. 14, 2021

Before we begin, let's discuss what is data seeding. Data seeding is the process of populating initial data to the database. This is a good option especially if you want to have an initial data stored in your database.

In Entity Framework Core, you have 3 options to achieve it. These are: Model seed data , Manual migration customization, and Custom initialization logic. source

In this demo, we're going to choose the mixed Model seed data & Custom initialization logic approach because what we want to do is create a data seed during migration and when the app starts to run whether locally or in the deployment environment.

FTF (First Things First)
  • Make sure you already prepared your ASP.NET Core application.
  • Your app has DbContext and connected to the database.

For our example, let's use the Person.cs model.

        namespace App.Models
{
  public class Person
  {
    [Key]
    public int PersonId { get; set; }
    public string Firstname { get; set; }
    public string Lastname { get; set; }
  }
}
      
Override OnModelCreating in your AppDbContext

1.1 If you can't find OnModelCreating inside your AppDbContext, declare it there to override the function and put our data seed.

        public class MyDbContext : DbContext
{
  public MyDbContext (DbContextOptions<MyDbContext> options) : base(options) {}

  protected override void OnModelCreating(ModelBuilder builder)
  {
    base.OnModelCreating(builder);

    builder.Entity<Person>()
      .HasData(new List<Person>
      {
        new Person {PersonId = 1, Firstname = "John", Lastname = "Doe"},
        new Person {PersonId = 2, Firstname = "Homer", Lastname = "Simpson"},
      });
  }

  public DbSet<Person> Persons { get; set; }
}
      

As you can see, we hardcoded the PersonId so everytime the app runs the data seed, it has already a declared primary key.

2. Create migration file and update the database.

2.1. Run create migration file script: dotnet ef migrations add CreateDataSeed

Data Seed in ASP.NET Core & EF Core | Mark Deanil Vicente

2.2. Update database: dotnet ef database update

Data Seed in ASP.NET Core & EF Core | Mark Deanil Vicente
3. Call the migration when the app starts to run via Program.cs

Alternatively, you can directly call the dbcontext and the migration inside the public static void Main(string[] args), but in the following steps, we will create an extension method for IHost so we can just call it in our Program.cs after the CreateHostBuilder(args).Build(). This way, we can make our Program.cs cleaner and also for code readability.

3.1 Install this nuget package Microsoft.AspNetCore.Hosting.Abstractions

Install-Package Microsoft.AspNetCore.Hosting.Abstractions -Version 2.2.0

3.2 Create extension file and let's call it: MigrationUtil

        public static class MigrationUtil
{
    public static IHost MigrateDb(this IHost host)
    {
        using var scope = host.Services.CreateScope();
        using var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
        try
        {
            context.Database.Migrate();
        }
        catch (Exception e)
        {
            Debug.WriteLine(e);
            throw;
        }

        return host;
    }
}
      

3.3 Call it in Program.cs

        public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().MigrateDb().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}
      

To test this, change the connection string then target a new database and run the application. (Make sure you still have the previous migrations like the CreateTable etc. to migrate the database properly)

Optional: Create extension method for ModelBuilder

If you don't want your OnModelCreating to be chunky with many HasData declarations in the future, then creating an extension method for ModelBuilder is a good option.

        public static ModelBuilder SeedEntitites(this ModelBuilder builder)
{
    // Seed person
    builder.Entity<Person>().HasData(new List<Person>
    {
        new Person {PersonId = 1, Firstname = "Test", Lastname = "Test"},
        new Person {PersonId = 2, Firstname = "Test2", Lastname = "Test2"}
    });

    // Seed other more...

    return builder;
}
      
Usage
        protected override void OnModelCreating(ModelBuilder builder)
{
    base.OnModelCreating(builder);

    builder.SeedEntitites();
}
      
That's it. I hope this post becomes helpful to you. Stay safe!

If you have some questions or comments, please drop it below 👇 :)

Buy Me A Tea