13

I can't figure out why my latest migration is not getting executed automatically on application startup (or at least on first access of the database context). I used to run update-database manually in development, but I want to test whether it will upgrade automatically on my hosted test environment.

In Application_Start():

Database.SetInitializer<FepazoContext>(
    new MigrateDatabaseToLatestVersion<FepazoContext, FepazoConfiguration>())

In FepazoConfiguration:

internal sealed class FepazoConfiguration : 
    DbMigrationsConfiguration<Fepazo.Models.FepazoContext>
{
    public FepazoConfiguration()
    {
        AutomaticMigrationsEnabled = true;
    }
}

I even added this to the constructor of FepazoContext:

public FepazoContext() : base("DefaultConnection")
{
    Database.Initialize(false);
}

Some extra information:

  • The migration was automatically created through add-migration and looks ok.
  • When I query the __MigrationHistory table, I can see that the migration is not yet 'recorded' as executed.
  • I verified that the initializer or the AutomaticMigrationsEnabled setting isn't overridden in Web.config file.
  • Breakpoints in FepazoContext constructor and the FepazoConfiguration are getting hit.

Am I forgetting something ? Can I dig deeper to find out where it goes wrong ?

Updates

Passing True to Database.Initialize to try and force the migration also has no effect. Database.CompatibleWithModel(true) returns false - so the system detects there is a difference, however it does not execute the pending migration!

public FepazoContext() : base("DefaultConnection")
{
    if (!Database.CompatibleWithModel(true))
    {
        // This is executed (each time the code enters)
        Database.Initialize(true);
    }
}

Workaround

As a workaround, I call DbMigrator.Update() explicitly right after setting the initializer. That does the trick, although I'd still like to know why it doesn't work automatically...

protected void Application_Start()
{
    // <...>
    Database.SetInitializer<FepazoContext>(
        new MigrateDatabaseToLatestVersion<FepazoContext, FepazoConfiguration>());
    var dbMigrator = new DbMigrator(new FepazoConfiguration());
    dbMigrator.Update();
    // <...>
}
Vincent Sels
  • 2,711
  • 1
  • 24
  • 31

4 Answers4

7

According to another answer on here the initializer doesn't run until there is some interaction with the database. The answer explains how to force the initializer to run immediately.

Community
  • 1
  • 1
Appetere
  • 6,003
  • 7
  • 35
  • 46
  • 1
    Of course, that's why I added "(or at least on first access of the database context)" in my first sentence, and why I said I tried `Database.Initialize(true);` without effect. Unfortunately the solution to this problem isn't that straightforward ;) – Vincent Sels Oct 25 '13 at 14:39
  • Wow, I spend 15 min looking into this issue, as I was starting my app but not logging in (/interacting with application), indeed it must interact with DB to perform the migration : ' ) – edencorbin Feb 12 '18 at 14:57
  • More specifically it's not just about interaction with the database, but specifically interaction with a potentially affected table in that database. – Inez Nov 18 '22 at 05:21
2

In the above code snippet you are calling the Database.Initialize() method immediately after creating a context instance. In this case, the database will be created immediately after calling the Initialize() method instead of waiting until the context is used for the first time.

The Initialize() method takes a Boolean parameter that controls whether the initialization process should re-run if it has already run for the application.

Specifying false will skip the initialization process if it has already executed. A value of true will initialize the database again even if it was already initialized.

SeyedPooya Soofbaf
  • 2,654
  • 2
  • 29
  • 31
  • Thanks for your answer. That doesn't explain why the system doesn't detect that it has to update the database using the latest migration though. I tried passing `true` as parameter to `Database.Initialize()` to force the upgrade, but even that doesn't execute it. – Vincent Sels Sep 01 '13 at 08:48
2

I had this issue. My problem turned out to be that I had a MigrationsContextFactory that was being used to provide the connection string. When the database initialization was occurring the migration context factory was being called. This MigrationsContextFactory was getting a connection string to a different database and was ensuring that was up to date.

I removed the MigrationsContextFactory and passed true to MigrateDatabaseToLatestVersion<,> Migrator to tell it to use the current context. See this question top voted answer How do I inject a connection string into an instance of IDbContextFactory<T>?

Community
  • 1
  • 1
GraemeMiller
  • 11,973
  • 8
  • 57
  • 111
  • I assumed that since `IDatabaseInitializer.InitializeDatabase(TContext)` accepted a `TContext` parameter it always just would use the supplied context. All of the other built-in initializers don’t even have that option, so it’s weird that they gave it inconsistent behavior with the rest of the framework. (Sorry for rant). – binki Jun 19 '18 at 19:57
2

Make sure the MigrateDatabaseToLatestVersion will be using the correct context that the application is using. This is done by using the parameter useSuppliedContext.

Database.SetInitializer<FepazoContext>(
    new MigrateDatabaseToLatestVersion<FepazoContext, FepazoConfiguration>(useSuppliedContext: true));

After this change, my MVC application did update my database.