EF Core Seed data means pre-populating the database with default data. This is useful in scenarios where you want to provide some test data in the development environment. You could use this to set up the application for the first time in a production environment by providing the sample or useful master data.
Source Code:
The source code of this project available in GitHub.
Table of Contents
How to Seed Data in EF Core
In the EF Core, the database seeding has now become part of the Model Configuration. We discussed how to Configure the model using the Fluent API. This is done by overriding the OnModelCreating
method.
OnModelCreating
The OnModelCreating
method is called by the Context when it initializes the Model for the first time. The Context passes the reference to the ModelBuilder
Instance in the OnModelCreating
method.
We override the OnModelCreating
method, where we get the reference to the Modelbuilder
instance. We can use the HasData
method of the ModelBuilder
to seed the initial data into the database via migrations.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public class EFContext : DbContext { private const string connectionString = "Server=(localdb)\\mssqllocaldb;Database=EFCoreDataSeed;Trusted_Connection=True;"; protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer(connectionString); } public DbSet<Department> Department { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { //Configure domain classes using modelBuilder here } } |
HasData
The HasData
method was introduced in EF CoOre 2.1. It is part of the EntityTypeBuilder<T>
property of the ModelBuilder
API, which we discussed in the Tutorial EF Core Fluent API,
Example of Seeding Data
The following code shows the Example of Seeding Data in EF Core. Consider the Department Model as shown below
1 2 3 4 5 6 7 | public class Department { public int DepartmentID { get; set; } public string Name { get; set; } } |
To Seed data in the Department table, First we need to override the OnModelCreating
method
Next, we get the reference to the EntityTypeBuilder
using the code;
1 2 3 | modelBuilder.Entity<Department>() |
Finally, use the HasData
method to supply the list of Departments as shown above
1 2 3 4 5 6 7 8 9 10 11 12 | protected override void OnModelCreating(ModelBuilder modelBuilder) { //Department modelBuilder.Entity<Department>() .HasData( new Department { DepartmentID = 1, Name = "HR" }, new Department { DepartmentID = 2, Name = "Admin" }, new Department { DepartmentID = 3, Name = "Production" }); } |
Once you have added the initial data, you should use migrations to update the database
The ID/Key values must be supplied in HasData
method. The EF Core will not generate these when using the HasData
method. While inserting the data, the SQL Server will enable the insertion of Identity values. Also do not change the value of the Primary key.
Migrations
Unlike its predecessor entity framework, the EF Core data seeding works with the migrations. Hence we need to create the ef core migration to update the database.
1 2 3 | add-migration "v1" |
and then update the database using update-database
or use the script-migration
to generate the SQL Script
1 2 3 4 5 | update-database or script-migration |
Updating the Seeded data
You can update the seeded data or add new data later by simply modifying the HasData
method. For Example the following code changes the Department name from Production to Development
1 2 3 4 5 6 7 8 9 | //Department modelBuilder.Entity<Department>() .HasData( new Department { DepartmentID = 1, Name = "HR" }, new Department { DepartmentID = 2, Name = "Admin" }, new Department { DepartmentID = 3, Name = "Development" } ); |
Run the add-migration v2
and update-database
to update the database with the new department name.
Do not change the value of Primary key i.e DepartmentID
. Because EF core uses it to check if any changes made to the record. If the changed field is a Foreign key, then the migration script will delete and recreate all the related records.
Never use some key generator functions for any field. For Example Guid.NewGuid()
for a Guid
field. DateTime.Now
for a DateTime
field. This will result in a new migration as the value changes every time you run the add-migration
command. Hence always use hardcoded values.
The related data is also added using the HasData
method,
The following is the complete example of how to seed the database when various types of relationships are present.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | public class Employee { [Key] public int EmployeeID { get; set; } public string Name { get; set; } [ForeignKey("Department")] public int DepartmentID { get; set; } public virtual Department Department { get; set; } public virtual EmployeeAddress EmployeeAddress { get; set; } public virtual ICollection<EmployeesInProject> Projects { get; set; } } public class EmployeeAddress { [Key, ForeignKey("Employee")] public int EmployeeID { get; set; } public string Address { get; set; } public virtual Employee Employee { get; set; } } public class Department { public int DepartmentID { get; set; } public string Name { get; set; } public virtual ICollection<Employee> Employees { get; set; } } public class Project { public int ProjectID { get; set; } public string Name { get; set; } public virtual ICollection<EmployeesInProject> Employees { get; set; } } public class EmployeesInProject { public int EmployeeID { get; set; } public int ProjectID { get; set; } [ForeignKey("EmployeeID")] public Employee Employee { get; set; } [ForeignKey("ProjectID")] public Project Project { get; set; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | protected override void OnModelCreating(ModelBuilder modelBuilder) { //Configure domain classes using modelBuilder here modelBuilder.Entity<EmployeesInProject>() .HasKey(e => new { e.EmployeeID, e.ProjectID }); modelBuilder.Entity<Department>() .HasData( new Department { DepartmentID = 1, Name = "HR" }, new Department { DepartmentID = 2, Name = "Admin" }, new Department { DepartmentID = 3, Name = "Development" } ); modelBuilder.Entity<Project>() .HasData( new Project { ProjectID = 1, Name = "Cricket" }, new Project { ProjectID = 2, Name = "Politics" }, new Project { ProjectID = 3, Name = "Boxing" }, new Project { ProjectID = 4, Name = "Racing" }, new Project { ProjectID = 5, Name = "Football" }, new Project { ProjectID = 6, Name = "Tennis" } ); modelBuilder.Entity<Employee>() .HasData( new Employee { EmployeeID = 1, Name = "Rahul Dravid", DepartmentID =1 }, new Employee { EmployeeID = 2, Name = "Trump", DepartmentID = 1 }, new Employee { EmployeeID = 3, Name = "Barak Obama", DepartmentID = 2 }, new Employee { EmployeeID = 4, Name = "Virat Kohli", DepartmentID = 2 }, new Employee { EmployeeID = 5, Name = "Muhammad Ali", DepartmentID = 3 }, new Employee { EmployeeID = 6, Name = "Michael Schumacher", DepartmentID = 3 }, new Employee { EmployeeID = 7, Name = "Lionel Messi", DepartmentID = 2 }, new Employee { EmployeeID = 8, Name = "Rafael Nadal", DepartmentID = 3 } ); modelBuilder.Entity<EmployeeAddress>() .HasData( new EmployeeAddress { EmployeeID = 1, Address = "Bangalore, India" }, new EmployeeAddress { EmployeeID = 2, Address = "Newyork, USA" }, new EmployeeAddress { EmployeeID = 3, Address = "California, USA" }, new EmployeeAddress { EmployeeID = 4, Address = "NewDelhi, India" }, new EmployeeAddress { EmployeeID = 5, Address = "Kentuki, USA" }, new EmployeeAddress { EmployeeID = 6, Address = "Hurth, Germany" }, new EmployeeAddress { EmployeeID = 7, Address = "Rosario, Argentina" }, new EmployeeAddress { EmployeeID = 8, Address = "Manacor, Spain" } ); modelBuilder.Entity<EmployeesInProject>() .HasData( new EmployeesInProject { EmployeeID = 1, ProjectID = 1 }, new EmployeesInProject { EmployeeID = 1, ProjectID = 4 }, new EmployeesInProject { EmployeeID = 2, ProjectID = 2 }, new EmployeesInProject { EmployeeID = 2, ProjectID = 3 }, new EmployeesInProject { EmployeeID = 3, ProjectID = 2 }, new EmployeesInProject { EmployeeID = 3, ProjectID = 5 }, new EmployeesInProject { EmployeeID = 4, ProjectID = 1 }, new EmployeesInProject { EmployeeID = 4, ProjectID = 3 }, new EmployeesInProject { EmployeeID = 5, ProjectID = 3 }, new EmployeesInProject { EmployeeID = 5, ProjectID = 2 }, new EmployeesInProject { EmployeeID = 6, ProjectID = 4 }, new EmployeesInProject { EmployeeID = 6, ProjectID = 2 }, new EmployeesInProject { EmployeeID = 7, ProjectID = 5 }, new EmployeesInProject { EmployeeID = 7, ProjectID = 1 }, new EmployeesInProject { EmployeeID = 8, ProjectID = 6 }, new EmployeesInProject { EmployeeID = 8, ProjectID = 5 } ); } |
Moving Seed Data to Separate File
The seeding method can get bigger and it would be a lot cleaner if we able to move the method to a separate class file. This is done by creating the extension method and calling the method from the OnModelCreating
.
Create a class named ModelBuilderExtensions.cs and add the static seed method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public static class ModelBuilderExtensions { public static void Seed(this ModelBuilder modelBuilder) { //Department modelBuilder.Entity<Department>() .HasData( new Department { DepartmentID = 1, Name = "HR" }, new Department { DepartmentID = 2, Name = "Admin" }, new Department { DepartmentID = 3, Name = "Development" } ); } } |
You can then call the Seed
method from the OnModelCreating
as shown below
1 2 3 4 5 6 7 8 9 | protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<EmployeesInProject>() .HasKey(e => new { e.EmployeeID, e.ProjectID }); modelBuilder.Seed(); } |
References
Read More
- EF Core Migrations
- Reverse Engineer Database (Database First)
- EF Core Data Seeding to the Database
- EF Core Script MIgration
Will this work even if the table has an identity coloumn?