Model-Based Seeding with HasData
HasData(), called inside OnModelCreating on an entity type builder, lets you declare static seed rows as part of the model itself. EF Core treats this data as part of the model, meaning any change to seed values generates a migration with explicit InsertData, UpdateData, or DeleteData operations the next time you run migrations add. This makes seed data versioned and reproducible across every environment, but it requires you to specify primary key values explicitly since EF Core cannot resolve identity or generated values at model-build time.
Cricket analogy: It's like a tournament's official rulebook printing the fixed opening-day squad list in advance — any roster change later must be issued as a formal amendment, not a quiet edit to the original list.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Role>().HasData(
new Role { Id = 1, Name = "Admin" },
new Role { Id = 2, Name = "Member" },
new Role { Id = 3, Name = "Viewer" }
);
}Imperative Seeding at Startup
For data that depends on runtime conditions, configuration values, or external calls, imperative seeding — calling a static SeedAsync method after context.Database.Migrate() in Program.cs — checks a condition such as if (!await context.Products.AnyAsync()) before inserting rows. This gives full control over conditional and dynamic logic, but the inserted data bypasses the migration history entirely, so it is not versioned, not tracked in __EFMigrationsHistory, and not automatically reversible the way HasData rows are.
Cricket analogy: It's like a ground curator deciding on match morning whether to add extra covers based on the weather forecast — a judgment call made at runtime, not something printed in the fixed pre-season schedule.
Environment-Specific and Idempotent Seeding
Production seed data for reference or lookup tables should be idempotent and safe to re-run — typically using existence checks before AddRange(), or database-specific upsert syntax such as ON CONFLICT DO NOTHING in PostgreSQL — so rerunning a deployment never creates duplicates. Environment-specific test or demo data, on the other hand, should live in separate seed classes gated by a check like if (env.IsDevelopment()), ensuring large synthetic datasets used for local testing or demos never run against a production database.
Cricket analogy: It's like a ground crew re-marking the boundary rope before every match using fixed reference pegs, so repeating the process never shifts the boundary even if done twice by different crews.
A practical rule of thumb: use HasData for small, stable reference data that rarely changes and benefits from being versioned in migrations, such as fixed roles or status enums. Use imperative seeding for larger datasets, environment-specific demo data, or seed data that depends on runtime configuration or external services.
- HasData() declares seed rows as part of the model, generating InsertData/UpdateData/DeleteData migration operations.
- HasData requires explicit primary key values because EF Core cannot resolve generated identities at model-build time.
- Imperative seeding runs custom code at startup, giving full control over conditional or dynamic seed logic.
- Imperative seed data bypasses migration history and is not automatically versioned or reversible.
- Production reference-data seeding should be idempotent using existence checks or database upsert syntax.
- Environment-specific demo or test data should be gated behind environment checks to avoid running in production.
- HasData suits small, stable reference data; imperative seeding suits large or environment-dependent datasets.
Practice what you learned
1. Why must you specify explicit primary key values when using HasData()?
2. What is a key drawback of imperative seeding compared to HasData?
3. What technique keeps large demo datasets from being seeded into a production database?
4. What migration operations does EF Core generate when you change a value inside HasData()?
Was this page helpful?
You May Also Like
Migrations Fundamentals
Learn how EF Core migrations track model changes and generate versioned database schema updates while preserving existing data.
Applying and Reverting Migrations
How to apply pending migrations to a database, generate deployable SQL scripts, and safely roll back schema changes.
Handling Schema Drift in Teams
Strategies for detecting and resolving mismatches between the EF Core model, migration history, and the actual database schema across a team.
Related Reading
Related Study Notes in Microsoft Technologies
Browse all study notesWindows 10 / UWP Development Study Notes
.NET · 30 topics
Microsoft TechnologiesWindows Batch Scripting Study Notes
Batch · 30 topics
Microsoft TechnologiesMFC (Microsoft Foundation Classes) Study Notes
C++ · 30 topics
Microsoft TechnologiesSilverlight Study Notes
.NET · 30 topics
Microsoft TechnologiesXAML Study Notes
.NET · 30 topics
Microsoft TechnologiesWPF (Windows Presentation Foundation) Study Notes
.NET · 30 topics