Applying Seed Data To The Database

Seed data is data that you populate the database with at the time it is created. You use seeding to provide initial values for lookup lists, for demo purposes, proof of concepts etc.

OnModelCreating

As of version 2.1, Entity Framework Core has a formal API for applying seed data to the database as part of your migration - the HasData method of the EntityTypeBuilder<T> method, which is exposed by the ModelBuilder.Entity<T> method, accessible in the OnModelCreating method of the DbContext class. So, basically, seeding forms part of model configuration.

The following example illustrates seeding by adding an entry to the Authors table:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Author>().HasData(
        new Author
        {
            AuthorId = 1,
            FirstName = "William",
            LastName = "Shakespeare"
        }
    );
}

The key value is required so it must be supplied. When a migration is created, the SQL Server provider will enable the insertion of Identity values:

SET IDENTITY_INSERT [Authors] ON;
INSERT INTO [Authors] ([AuthorId], [FirstName], [LastName])
VALUES (1, N'William', N'Shakespeare');
SET IDENTITY_INSERT [Authors] OFF;

Related data must be added separately via the HasData method applied to the related entity's EntityTypeBuilder. Here is how you can add an author together with related books:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Author>().HasData(
        new Author
        {
            AuthorId = 1,
            FirstName = "William",
            LastName = "Shakespeare"
        }
    );

    modelBuilder.Entity<Book>().HasData(
        new Book { BookId = 1, AuthorId = 1, Title = "Hamlet" },
        new Book { BookId = 2, AuthorId = 1, Title = "King Lear" },
        new Book { BookId = 3, AuthorId = 1, Title = "Othello" }
    );
}

Note that the Identity value for each book is provided, and that the Foreign Key value has been set to that of the seed Author.

If you prefer to keep your OnModelCreating method clean, you can refactor these operations into an extension method on the ModelBuilder type:

public static class ModelBuilderExtensions
{
    public static void Seed(this ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Author>().HasData(
            new Author
            {
                AuthorId = 1,
                FirstName = "William",
                LastName = "Shakespeare"
            }
        );
        modelBuilder.Entity<Book>().HasData(
            new Book { BookId = 1, AuthorId = 1, Title = "Hamlet" },
            new Book { BookId = 2, AuthorId = 1, Title = "King Lear" },
            new Book { BookId = 3, AuthorId = 1, Title = "Othello" }
        );
    }
}

Then you can call the Seed method in OnModelCreating:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Seed();
}

Amending Seed Data

You can add or alter seed data during subsequent migrations. Entity Framework Core will compare the data in the database and generate the appropriate insert, update and delete methods.

Before Entity Framework Core 2.1

Previous to version 2.1, the advice was to create code for adding the seed data and then to call that code along with other application startup code in Program.Main().

The following code illustrates this pattern, starting with a method that seeds the database with countries:

public class DataSeeder
{
    public static void SeedCountries(DbContext context)
    {
        if (!context.Countries.Any())
        {
            var countries = new List<Country>
            {
				new Country { Name = "Afghanistan" },
				new Country { Name = "Albania" },
				new Country { Name = "Algeria" },
				new Country { Name = "Andorra" },
				new Country { Name = "Angola" },
				new Country { Name = "Antigua and Barbuda" },
				new Country { Name = "Argentina" },
				new Country { Name = "Armenia" },
				new Country { Name = "Aruba" },
				new Country { Name = "Australia" },
				new Country { Name = "Austria" },
				new Country { Name = "Azerbaijan" },
                ...
            };
            context.AddRange(countries);
            context.SaveChanges();
        }
    }
}

While this example uses hardcoded country names (and is curtailed for brevity), the code could just as simply read seed data from an external location such as a web service, text or XML file.

The SeedCountries method is called in the Main method of the Progam class. This example ilustrates how this might be achieved in an ASP.NET application:

public void Main(string[] args)
{
    var host = BuildWebHost(args);
    using (var scope = host.Services.CreateScope())
    {
        var services = scope.ServiceProvider;
        var context = serviceScope.ServiceProvider.GetService<ApplicationDbContext>();
        DataSeeder.SeedCountries(context);
    }
    host.Run();
}

You could also refactor the code that calls the seed method into an extension method on IWebHost:

public static IWebHost SeedData(this IWebHost host)
{
    using (var scope = host.Services.CreateScope())
    {
        var services = scope.ServiceProvider;
        var context = serviceScope.ServiceProvider.GetService<ApplicationDbContext>();
        
        SeedCountries(context);
    }
    return host;
}

Then you can chain this method in the Program.Main method:

public void Main(string[] args)
{
    BuildWebHost(args).SeedData().Run();
}
Last updated: 18/07/2018 08:03:04

© 2018 - Learn Entity Framework Core.
All rights reserved.