0

I'm having trouble understanding the rules around when SeedData is called in EF Code First. Specifically, does it have anything to do with migrations? Migrations has it's own place to seed that seems different from the datacontext. I'm showing two examples below and I'm not sure which one is correct to use.

My Main Question: If I have a Migration, does the seeddata method not get called in my MultiTenantContext class? I have examples where it does and it does not and I can't figure out why.

In Migrations configuration.cs:

namespace WebApp.Migrations
{
using System;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Linq;

internal sealed class Configuration : DbMigrationsConfiguration<WebApp.Models.MultiTenantContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
        ContextKey = "WebApp.Models.MultiTenantContext";
    }

    protected override void Seed(WebApp.Models.MultiTenantContext context)
    {
        var tenants = new List<Tenant>
        {...};
        tenants.ForEach(a => context.Tenants.Add(a));
        context.SaveChanges();
        //  This method will be called after migrating to the latest version.

        //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
        //  to avoid creating duplicate seed data. E.g.
        //
        //    context.People.AddOrUpdate(
        //      p => p.FullName,
        //      new Person { FullName = "Andrew Peters" },
        //      new Person { FullName = "Brice Lambson" },
        //      new Person { FullName = "Rowan Miller" }
        //    );
        //
    }
 }
}

And in context class directly:

[DbConfigurationType(typeof(DataConfiguration))]
public class MultiTenantContext : DbContext
{
    public DbSet<Tenant> Tenants { get; set; }
}

public class DataConfiguration : DbConfiguration
{
    public DataConfiguration()
    {
        SetDatabaseInitializer(new MultiTenantContextInitializer());
    }
}

public class MultiTenantContextInitializer :
    CreateDatabaseIfNotExists<MultiTenantContext>
{
    protected override void Seed(MultiTenantContext context)
    {
        var tenants = new List<Tenant>
        {...}
        tenants.ForEach(a => context.Tenants.Add(a));
        context.SaveChanges();
    }
}
Peter Kellner
  • 14,748
  • 25
  • 102
  • 188
  • The Seed in your context is only going to be called when your database is created which depends on your initializer. The migration Seed() will get called every time you apply a migration (or even no migration) with update-database. Here is a great summary: http://blog.oneunicorn.com/2013/05/28/database-initializer-and-migrations-seed-methods/ – Steve Greene Jan 13 '16 at 21:46
  • Wow, is that confusing! Sadly I'm trying to explain that in a video without making the video all about that. How does Update-Database play in? It seems that when the db is created (I tried with drop-create-always) and unless I call update-database, nothing happens, and if I do, the data is added twice. – Peter Kellner Jan 13 '16 at 22:03
  • Well, the non-migration initializers are usually only good for early prototyping when you don't care about what's in the database. You can use that seed method to populate your lookup tables and add minor amounts of test data. Once you have anything you care about, switch to a migration initializer that doesn't trash the database when the model changes. Also, take a look at the AddOrUpdate command which is designed for seeding scenarios so you don't get duplicate data. http://thedatafarm.com/data-access/take-care-with-ef-4-3-addorupdate-method/ – Steve Greene Jan 13 '16 at 22:07
  • Great comments and links from @Steve. I would add that sometimes you may wish to add standing data with a specific migration, and a way of doing that is with the Sql command in the migration http://stackoverflow.com/a/18769531/150342 – Colin Jan 14 '16 at 09:21

0 Answers0