How can I get my database to seed using Entity Framework CodeFirst?

Solution 1:

This is what my DbContext classes all look like and they seed just fine:

public class MyDbContext : DbContext
{
    public DbSet<MyClass> MyClasses { get; set; }

    protected override void OnModelCreating (DbModelBuilder modelBuilder)
    {
        base.OnModelCreating (modelBuilder);
        modelBuilder.Conventions.Remove<System.Data.Entity.ModelConfiguration.Conventions.PluralizingTableNameConvention> ();

        // Add any configuration or mapping stuff here
    }

    public void Seed (MyDbContext Context)
    {
        #if DEBUG
        // Create my debug (testing) objects here
        var TestMyClass = new MyClass () { ... };
        Context.MyClasses.Add (TestMyClass);
        #endif

        // Normal seeding goes here

        Context.SaveChanges ();
    }

    public class DropCreateIfChangeInitializer : DropCreateDatabaseIfModelChanges<MyDbContext>
    {
        protected override void Seed (MyDbContext context)
        {
            context.Seed (context);

            base.Seed (context);
        }
    }

    public class CreateInitializer : CreateDatabaseIfNotExists<MyDbContext>
    {
        protected override void Seed (MyDbContext context)
        {
            context.Seed (context);

            base.Seed (context);
        }
    }

    static MyDbContext ()
    {
        #if DEBUG
        Database.SetInitializer<MyDbContext> (new DropCreateIfChangeInitializer ());
        #else
        Database.SetInitializer<MyDbContext> (new CreateInitializer ());
        #endif
    }
}

I have used this pattern a few times and it has worked out very well for me.

Solution 2:

My Seed method was not invoked even with proper call to Database.SetInitializer in Application_Start... The reason for it was really simple: initializer may not be invoked at all if you don't yet have any code that actually uses database context.

Solution 3:

This is my sad little tale.

First, lessons learned:

  1. The seed method won't be called until the context is used.
  2. The Global.asax.cs won't hit a breakpoint on first run bc it runs before the debugger is attached. To hit a breakpoint on Global.asax.cs, you have can add some white space to Web.config and hit a page; then it will get hit.
  3. If there are VS connections to the db, the seeding won't happen. The app will throw an error.

So, to avoid the sadness:

  • Disconnect your VS connection.
  • Switch the base class DropCreateDatabaseAlways for one go.
  • Hit a page that uses the context.

Now, the sadness:

  1. I had my custom Initializer class in my Global.asax.cs file. I had a break point on my Initializer Seed method; I started the application and the method never got hit. :(
  2. I point a break point in my Database.SetInitializer call in Application_Start. That never got hit. :(
  3. I realized that I had no db schema changes, so then I changed DropCreateDatabaseIfModelChanges to DropCreateDatabaseAlways. Still, nothing. :(
  4. I finally went to a page that uses the context, and it worked. :/