If you’re developing large scale database designs using Entity Framework, especially with Code First Migrations, you’ve likely wanted to seed some data. Perhaps it’s some constant lookup values or test data used in your local dev environments for on-boarding new team members. It’s also nice to run migrations on startup for when you are deploying to different environments!
This blog post is just a simple set of tools I commonly use to allow for automatically running migrations and seeding some data with some examples.
Basically we’ll:
- Design a Code First Database with EF Core
- Add a migration
- Build two different
Seeder
classes - Build an extension method to run Migrations and the
Seeders
when the application starts
This doesn’t care about how you actually setup your DbContext
within your app, what database provider you use, etc.
Database Design
Let’s go with a simple example of a Blog website database design. Let’s first add some POCOs for out entities then create our DbContext
.
Post.cs
public class Post { public long Id { get; set; } public string Title { get; set;} public string Content { get; set; } public string PostTypeId { get; set; } public virtual PostType PostType { get; set; } }
PostType.cs
public class PostType { public long Id { get; set; } public string Name { get; set; } public virtual ICollection Posts { get; set; } }
BlogContext.cs
public class BlogContext : DbContext { public DbSet Posts { get; set; } public DbSet PostTypes { get; set; } }
Add Migration
Now that we have a DbContext
and our tables, let’s create our migration!
In the Visual Studio Package Manager Console:
add-migration InitialCreate
or in the CLI:
dotnet ef migrations add InitialCreate
Building Seeder Classes
Now we have a database designed and a migration, so let’s create a seeder for creating some PostTypes
that should be the same for every environment and then another TestDataSeeder
to seed some examples for developers to use when running the app for the first time.
PostTypesSeeder
public class PostTypesSeeder { private readonly BlogContext _context; public PostTypesSeeder(BlogContext context) { _context = context; } public void SeedData() { AddNewType(new PostType { Id = 0, Name = "Standard" }); AddNewType(new PostType { Id = 1, Name = "Aside" }); AddNewType(new PostType { Id = 2, Name = "Snippet" }); _context.SaveChanges(); } // since we run this seeder when the app starts // we should avoid adding duplicates, so check first // then add private void AddNewType(PostType postType) { var existingType = _context.PostTypes.FirstOrDefault(p => p.Name == postType.Name); if(existingType == null) { _context.PostTypes.Add(postType); } } }
This seeder let’s us add 3 different PostTypes
if they don’t already exist.
TestDataSeeder.cs
public class TestDataSeeder { private readonly BlogContext _context; public TestDataSeeder(BlogContext context) { _context = context; } public void SeedData() { _context.Posts.Add(new Post { Name = "Test Post 1", Content = "This is my standard post for testing", PostTypeId = 0 }; _context.Posts.Add(new Post { Name = "Test Post 2", Content = "This is my aside post for testing", PostTypeId = 2 }; _context.SaveChanges(); } }
Building the WebHost Extension
Now that we have our seeders. Let’s build that extension method for running the migration and running this seeders.
WebHostExtensions.cs
public static class WebHostExtensions { public static IWebHost SeedData(this IWebHost host) { using (var scope = host.Services.CreateScope()) { var services = scope.ServiceProvider; var context = services.GetService(); // now we have the DbContext. Run migrations context.Database.Migrate(); // now that the database is up to date. Let's seed new PostTypesSeeder(context).SeedData(); #if DEBUG // if we are debugging, then let's run the test data seeder // alternatively, check against the environment to run this seeder new TestDataSeeder(context).SeedData(); #endif } return host; } }
Implementing the Extension
Now that we have our database and entities, seeders, and an extension method – let’s just drop it in our Program
class to run when we are creating the WebHost!
Program.cs
public class Program { public static void Main(string[] args) { CreateWebHostBuilder(args).Build().SeedData().Run(); } public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup(); }
Note: although this Program
is in the ASP.NET Core 2.1 style, the same code works in the original 2.0 style. Just stick it after the Build()
call wherever you run that.
And that’s it! Now we have always-up-to-date data whenever we run our ASP.NET Core app! 😀
If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!
Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.