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.
- Make sure you already prepared your
ASP.NET Coreapplication. - Your app has
DbContextand 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; }
}
}
OnModelCreating in your AppDbContext1.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.1. Run create migration file script: dotnet ef migrations add CreateDataSeed
2.2. Update database: dotnet ef database update
Program.csAlternatively, 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.03.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)
ModelBuilderIf 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;
}
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 👇 :)