Seed Data in EF Core

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.

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.

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

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;

modelBuilder.Entity<Department>()

Finally, use the HasData method to supply the list of Departments as shown above

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.

add-migration "v1"

and then update the database using update-database or use the script-migration to generate the SQL Script 

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

//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.

Seeding Related Data

The related data is also added using the HasData method,

Example of Seeding Related Data

The following is the complete example of how to seed the database when various types of relationships are present.

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; }
}
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.

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

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
  modelBuilder.Entity<EmployeesInProject>()
     .HasKey(e => new { e.EmployeeID, e.ProjectID });

  modelBuilder.Seed();
}

References

1 thought on “Seed Data in EF Core”

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top