62

The database is created successfully (as are the tables) but is not seeded. I have spent several hours and read tons of articles but have not been able to get it. Any suggestions?

On a side note, is it possible to call the initializer without having a reference to my DatabaseContext in the client?

I have included all the relevant code I could think of. If anything else would be helpful, please let me know.

Things I've Tried:

  1. I deleted my connection string (since it defaults to sqlexpress anyways, just the name changed)
  2. I changed DropCreateDatabaseIfModelChanges to DropCreateDatabaseAlways, still the same.

Edit: The really weird thing is it worked once, but I have no idea how or why it broke again. I am assuming connection strings, but who knows.

DatabaseInitializer.cs

public class DatabaseInitializer : DropCreateDatabaseIfModelChanges<DatabaseContext>
{
  protected override void Seed(DatabaseContext context)
  {
    // Seeding data here
    context.SaveChanges();
  }
}

DatabaseContext.cs

public class DatabaseContext : DbContext
{
  protected override void OnModelCreating(DbModelBuilder mb)
  {
    // Random mapping code
  }

  public DbSet<Entity1> Entities1 { get; set; }
  public DbSet<Entity2> Entities2 { get; set; }

}

Global.asax.cs - Application_Start()

protected void Application_Start()
{
  Database.SetInitializer<DatabaseContext>(new DatabaseInitializer());
  AreaRegistration.RegisterAllAreas();
  RegisterGlobalFilters(GlobalFilters.Filters);
  RegisterRoutes(RouteTable.Routes);
}

Client web.config

<connectionStrings>
  <add name="DatabaseContext" connectionString="data source=.\SQLEXPRESS;Database=Database;Integrated Security=SSPI;" providerName="System.Data.SqlClient" />
</connectionStrings>

SOLUTION

For the sake of documentation, I am sharing my solution here. Navigating all the comments would be a pain anyways. In the end I had DatabaseInitializer and DatabaseContext in separate classes. I don't really understand while these tiny changes fixed it, but here it is.

DatabaseInitializer.cs

public class DatabaseInitializer : CreateDatabaseIfNotExists<DatabaseContext>
{
  protected override void Seed(DatabaseContext context)
  {
    // Seed code here
  }
}

DatabaseContext.cs

public class DatabaseContext : DbContext
{
  public DatabaseContext() : base("MyDatabase") { }

  protected override void OnModelCreating(DbModelBuilder mb)
  {
    // Code here
  }

  public DbSet<Entity> Entities { get; set; }
  // Other DbSets
}

Global.asax.cs - Application_Start()

protected void Application_Start()
{
  Database.SetInitializer(new DatabaseInitializer());
  AreaRegistration.RegisterAllAreas();
  RegisterGlobalFilters(GlobalFilters.Filters);
  RegisterRoutes(RouteTable.Routes);
}
Jenn
  • 884
  • 8
  • 16
Alec
  • 1,646
  • 3
  • 19
  • 35
  • Are you adding the seed items to your data context? I know I've missed that before. – Jim D'Angelo Jun 10 '11 at 22:32
  • Yeah I am. Thanks for checking though :). – Alec Jun 10 '11 at 22:53
  • 1
    =D No worries. Can you put a break point in the code and make sure that your Seed is getting called? – Jim D'Angelo Jun 10 '11 at 23:16
  • The Seed method is not being called. DatabaseInitializer is. Am I missing something? – Alec Jun 13 '11 at 16:42
  • That's really weird. Try putting your Database.SetInitializer in the constructor of DatabaseContext. Also, try adding base.Seed (context); to your seed method. I don't know why this would matter, but it's worth checking. Edit: I saw your comment on @feanz's answer, but you can put the Database.SetInitializer in your datacontext's constructor. I acutlaly put my initilizer classes *inside* of my datacontext class. – Jim D'Angelo Jun 13 '11 at 17:28
  • Okay I can get the database to seed now, but I have a few further questions. The database now seeds whenever I call the DatabaseContext constructor, but shouldn't it seed when I use the Database.SetInitializer in the App_Start method? Currently it will not create the database and/or seed unless I actually explicitly call the DatabaseContext constructor. Edit: I will mark as answer for sure, no worries :) – Alec Jun 13 '11 at 18:59
  • When you use the context for the first time, it will seed the database using my setup, kind of a delayed load. You are definitely free to tweak it as you see fit. The reason I use this is so I don't have to keep shutting down Cassini or IIS Express (whichever I'm using at the time) to drop the database if I change my model. Once things stabalize, I then refactor to shift the seed at Application_Start. This is definitely just a preference, though. – Jim D'Angelo Jun 13 '11 at 19:04
  • Does it fire Seed when you use the DatabaseContext constructor or when you actually make a call using the DatabaseContext? Whether I make the Database.SetInitializer call in App_Start or the DatabaseContext constructor, Seed does not actually fire until I make a call using DatabaseContext. – Alec Jun 13 '11 at 19:07
  • Seed is going to be fired the first time you try to get anything from or put anything into the database. I wrap my DbContexts up into units of work and repositories, so it doesn't happen until I access data from a repository. – Jim D'Angelo Jun 13 '11 at 19:17

12 Answers12

37

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.

Jim D'Angelo
  • 3,952
  • 3
  • 25
  • 39
  • 2
    This is not the solution I exactly implemented, I have detailed my solution in the original question above. Just posting this comment for ease of use for future users. Thanks to jdangelo for all the help! – Alec Jun 13 '11 at 19:22
  • 1
    This is a great method for doing this because it doesn't require any changes to Application_Start() and therefore re-usable – xkingpin Feb 20 '14 at 18:29
10

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.

user1068352
  • 591
  • 6
  • 14
9

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. :/
Davious
  • 1,833
  • 2
  • 15
  • 16
  • this works and thanks for this useful info. I closed the database connection and then switched the base classto DropCreateDatabaseAlways. It worked well . – Rasshme Chawla Feb 01 '13 at 08:38
  • the Global only runs the first time. So close IISExpress. Set your break point in global and run. It will hit it, once, because its IIS application level. – Piotr Kula Nov 06 '14 at 20:22
3

You can call update-database to manually run the seed method inside the Configuration class. This requires enable-migrations to be on as well.

PM> update-database
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
No pending code-based migrations.
Running Seed method.

internal sealed class Configuration : DbMigrationsConfiguration<ProjectManager.Data.Database.ProjectDb>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
    }

    protected override void Seed(ProjectManager.Data.Database.ProjectDb context)
    {
        context.Status.AddOrUpdate(
            new Status() { Id = 1, Text = "New" },
            new Status() { Id = 2, Text = "Working" },
            new Status() { Id = 3, Text = "Completed" },
            new Status() { Id = 4, Text = "Skipped" }
        );
    }
}
Despertar
  • 21,627
  • 11
  • 81
  • 79
2

The following change in the Global.asax file worked for me:

Old Code:

    protected void Application_Start()
    {
        Database.SetInitializer<mycontextclassname>(new DropCreateDatabaseAlways<mycontextclassname>());             
       ...
    }

New Code:

    protected void Application_Start()
    {
        Database.SetInitializer<mycontextclassname>(new DropCreateDatabaseAlways<mycontextclassname>()); 
        Database.SetInitializer(new Initializer()); 
        ...
    }
1

I too have had difficulty getting Seed() to be invoked. And I do appreciate all the helpful suggestions above and have had some luck using DropCreateDatabaseAlways ... but not ALWAYS!!

Most recently, I added the following line of code in the the constructor of my Repository to good effect:

    public CatalogRepository()
    {
        _formCatalog.FormDescriptors.GetType();

    }

It was sufficient to trigger the Seed() getting invoked. If you've tried everything above this answer and still no luck, give it a try. Good luck this was really a time consuming experience.

Joe
  • 11
  • 1
0

I've just come across this problem. I've deleted the "connectionstrings" section from the Web.config file, and currently the app started running - without the connectionstrings section! I add the section back, and the database is not seeding again. It's not a proper solution, but I'm just adding a data point here to what can potentially solve the problem.

Fortunately it's just a small "throwaway" app I'll discard soon anyway ...

Evgeny
  • 3,320
  • 7
  • 39
  • 50
0

Updated to note that this answer is incorrect! The reason for my DB not getting seeded remains a mystery (but it wasn't the lack of a default base constructor call, as noted by @JaredReisinger)

I appreciate this question is a little old but I ended up here so someone else might. Here's my tuppence worth:

My DB was getting created fine but not seeded, even if I deleted the database and started again using DropDatabaseInitialiser.

After reading the code above I noticed that my context constructor was this

public MyApp_Context()
{
    // some code
}

whereas the example above would be as follows for my setup

public MyApp_Context() : base("name=MyApp_Context")
{
    // some code
}

Yup, I wasn't calling the base object's constructor! I wouldn't have expected everything except seeding to work in this instance but that appears to be the (repeatable) case.

NB, I don't actually need to supply the context name in the base constructor call; I only wrote it that way initially because I was copying the format of the solution above. So my code is now this, and seeding works on initial database creation.

public MyApp_Context() : base()
{
    // some code
}
Jon
  • 309
  • 3
  • 10
  • The base class's default constructor is automatically called any time you don't call a specific variant of it directly. See http://stackoverflow.com/questions/13166019/will-the-base-class-constructor-be-automatically-called for further details. – JaredReisinger Oct 29 '16 at 19:14
  • Yes, I would have to agree with you. The only thing is, when I wrote that three years ago I seemed to have noticed that omitting the (redundant) base() call led to a different result than including it. I might dig that code out at some point, but it's probably safest to assume that there was some other effect exerting itself there. – Jon Nov 08 '16 at 16:45
0

Meticulously ensure that you didn't declare your context variable more than once. If you declare it again after seeding, the seed will be overwritten.

KSHMR
  • 741
  • 1
  • 9
  • 24
0

I was having same problem and after change in both Global.asax file and Intializer file it worked. I hope it will work for those who are still having problem for data seeding.

New Code in Global.asax:

    protected void Application_Start()
    {
        Database.SetInitializer<mycontextclassname>(new DropCreateDatabaseAlways<mycontextclassname>()); 
        Database.SetInitializer(new Initializer()); 
        ...
    }

code for Intializer file:

public class Initializer : System.Data.Entity.DropCreateDatabaseAlways<Context>
Gergely Toth
  • 6,638
  • 2
  • 38
  • 40
0

The seed event in your example will only be fired once as your using DropCreateDatabaseIfModelChanges you can change this to DropCreateDatabaseAlways i think and it should fire the seed event every time.

Edit

This is my DataContext

public WebContext()
{   
    DbDatabase.SetInitializer(new DropCreateDatabaseIfModelChanges<WebContext>());
}
Richard Forrest
  • 3,567
  • 2
  • 23
  • 32
  • I tried switching. No luck. Still created the database and all the tables but did not seed. – Alec Jun 10 '11 at 21:55
  • I call the Database.SetInitializer(new DatabaseInitializer()); in the constructor of the DatabaseContext which works for me – Richard Forrest Jun 11 '11 at 09:21
  • I can't reference DatabaseInitializer in DatabaseContext as that would be a circular reference. Also it should not need to go in the DatabaseContext constructor, as it should be called by the DatabaseInitializer constructor in App_Start (as far as my understanding goes). – Alec Jun 13 '11 at 16:48
0

This just happened to me while I was discovering Code First Features. This situation often happens when you have first used Code First to generate your database without any initialization strategy.

If you decide to do so later on by implementing a DropCreateDatabaseIfModelChanges based strategy, but without modifying you model, then your Seed method won't be called since the database generation and your strategy will only be applied next time you change your model.

If this happens to you, just try to modify your model a bit to test this hypothesis and I bet, your database is going to be populated ;)

I don't have the solution yet, except using a strategy that always generate the database, but I'm really not confortable with the fact of putting the initialization strategy in your DbContext since this class is goind to be used in you production environement, althought the initialization strategy seems to be mostly used for fluent developement environnement.

Bruno
  • 1,944
  • 13
  • 22