November 2014

Volume 29 Number 11


Data Points : A Code First Migrations Mystery: Solved

Julie Lerman | November 2014

Julie LermanA friend recently asked me a question about Entity Framework (EF) Code First Migrations that confused me almost as much as it confused him—but for different reasons.

The conversation went something like this:

“Hey Julie, why would my Azure Web site automatically migrate my database?”

“Are you sure you don’t have automatic migrations set to true? It’s false by default.”

“Definitely not. I did not change that setting.”

“What about the migrations initializer? That could do it, too.”

Let me interrupt here and make sure you truly understand about that initializer. If migrations are explicit, something you create and execute in the Package Manager Console, why is there an initializer?

Code First Initializers

Code First started out with three initializers:

CreateDatabaseIfNotExists: With this one, if the database isn’t found it will be created, and that’s the end of its job. If you modify the database, the database won’t be recreated or migrated. You’ll simply get an exception suggesting you use a different method to manage the database. Specifically, the suggestion will be to use migrations.

DropCreateDatabaseAlways: This one’s ideal for integration testing. It will delete the existing database and recreate it from scratch, running any seed logic you’ve added in. For integration testing, it’s a great way to always have a consistent database.

DropCreateDatabaseIfModelChanges: Before there were migrations, this was a useful option during development, if you didn’t need to retain data or any other schema you might have changed in the database such as adding indexes or triggers.

For completeness, I’d like to also point out that in EF6, we got the NullDatabaseInitializer for those who find it hard to remember (or discover) the other syntax for disabling initialization: SetDatabaseInitialier<MyContext>(null).

Then migrations arrived in EF4.3. Migrations aren’t active in your data layer until you explicitly enable them from the Package Manager Console Window by typing enable-migrations. All this really does is add a new folder with a Configuration class to your project. If the enable process discovers an existing database tied to your context, it creates an initial migration class, as well. This is to ensure that when you execute migrations, Code First doesn’t attempt to create an already existing database object.

In fact, you’ll see an informational message in the console after enabling migrations, as shown in Figure 1.

The Enable-Migrations Response to Existing Database Created by an Initializer
Figure 1: The Enable-Migrations Response to Existing Database Created by an Initializer

If you look in your database, in the new __MigrationHistory file, you’ll see a row in the table reflecting that the initial migration has already been executed on the database.

It’s important to understand there is nothing else—no additions to your application config or any other hidden pieces to the migration puzzle. The Configuration class is critical, though.

Here’s the default implementation from when I enabled migra­tions on my data layer, where I have a DbContext class called MigratoryBirdsContext:

internal sealed class Configuration : 
  DbMigrationsConfiguration<MigratoryBirdsContext>
  {
    public Configuration()
    {
      AutomaticMigrationsEnabled = false;
      ContextKey = "DataLayer.MigratoryBirdsContext";
    }
    protected override void Seed(MigratoryBirdsContext context)
    {
    }
  }

Because I’ll be using this class explicitly further on, I’ll change its signature to public. For those of you simply scanning through the code, here’s the new declaration:

public class Configuration : DbMigrationsConfiguration<MigratoryBirdsContext>

Migrations can run automatically, meaning that model changes will be discovered and migrations corresponding to changes will be created and executed on the database. All of this happens at run time during database initialization. Automatic migrations are handy for simple apps, but you have very little control over them and I typically don’t recommend enabling them. I was happy when Code First switched the default to false.

At run time, Code First looks for a DbMigrationsConfiguration class that’s tied to a context when that context goes through its data­base initialization process. If that class is found, any explicit calls or settings to set database initialization to any of the original three initializers—whose job is to create or drop and create the database—will create the database using the migrations. This is a new pattern for EF6.1. Prior to that, those three initializers would use the initialization logic they had always used since EF4.3, by inferring the database schema from the model and configurations. This change to EF6.1 is convenient for developers who, like me, use the DropCreateDatabase­Always initializer in their tests. Now it will drop the database but use my migrations to recreate it. If I’ve customized my migrations classes, I’ll get that customization applied to my database, as well.

It’s also important to keep in mind that the default initializer—CreateDatabaseIfNotExists—will also use migrations to create a database if the migrations exist but the database doesn’t.

So, now I can look at the fourth initializer, MigrateDatabaseToLatestVersion, which is the one I asked my friend about when he was trying to get to the source of the mysterious migrations in his Azure Web site. This initializer has been around since migrations were introduced in EF4.3.

The name, MigrateDatabaseToLatestVersion, seems to suggest it would work much like automatic migrations, but there’s a single, significant difference. Automatic migrations are triggered by a change in the model, whereas this initializer’s task is triggered by existing migration classes.

To see how this works, let’s start with the default state after you’ve enabled migrations. There’s no MigrateDatabaseToLatestVersion initializer in play and AutomaticMigrations is set to false.

Here’s a basic integration test that executes a simple query on MigratoryBirdsContext:

[TestMethod]
public void CanInitializeDatabase() {
  using (var context = new MigratoryBirdsContext())
  {
    context.MigratoryBirds.ToList();
  }
  Assert.Inconclusive("If we're here, it did not crash");
}

If I were to make a change to one of the classes in my model and run this test, an exception would be thrown, telling me, “The model backing the MigratoryBirdsContext context has changed since the database was created. Consider using Code First Migrations to update the database.”

Even though migrations have been enabled and I do have the MigrationsConfiguration class, all that EF knows is that the current model doesn’t match the latest version stored in the MigrationHistory table. At this point, I could use add-migration and update-database to fix the problem, but I want to show you how the initializer works, so I’ll take a different path: I’ll modify the test to enable the initializer. If you’re not familiar with its constructor syntax, you have to point to the Configuration file along with the target DbContext, like so:

[TestMethod]
public void CanInitializeDatabase()
{
  Database.SetInitializer(
    new MigrateDatabaseToLatestVersion<MigratoryBirdsContext, 
    DataLayer.Migrations.Configuration>());
  using (var context = new MigratoryBirdsContext())
  {
    context.MigratoryBirds.ToList();
  }
  Assert.Inconclusive("If we're here, it did not crash");
}

Running the test again throws another exception, and its message highlights the difference between this initializer and automatic migrations: “Unable to update database to match the current model because there are pending changes and automatic migration is disabled. Either write the pending model changes to a code-based migration or enable automatic migration.”

AutomaticMigrations would note the difference, create the migration and update the database—all on-the-fly and quietly. However, AutomaticMigrations doesn’t persist any migrations it creates as a class in your project. Although this initializer notes the change, it doesn’t automatically create the migration for you. It can work only with existing migrations.

If you haven’t performed migrations manually before, it’s a two-step process:

First, you create the migration with the add-migration command. This will read your model and query the database for the latest entry in the migration history table, then compare the two. If your model has changed since it was last stored, it will create a new migration class with instructions for migrating the current schema of the database to align with the changes in your model. Next, you execute that migration (or some combination of migrations based on the command syntax) on the database. The base command you type into the Package Manager Console is update-database.

Not many developers realize you can perform the update database programmatically, as well. I knew it was possible, but hadn’t done it in so long I actually had to go look for the details in my Code First Migrations course on Pluralsight. The migrations API has a DbMigrator class that lets you update the database with the same options you have access to from the update-database command in the console.

The key steps are to instantiate your migration configuration file; instantiate the API DbMigrator class, passing in an instance of your migration Configuration class; and then call Update:

var migrator = new DbMigrator(new DbMigrationsConfiguration());
migrator.Update();

And this is what the MigrateDatabaseToLatestVersion initializer does on your behalf. The migrations need to already exist in your project (or in your compiled assembly) and the initializer will execute them on the database for you at run time.

With that change I’ve made to my domain class, I’ll now go ahead and add a migration with the command add-migration ‘JetStream.’ Here’s the class that gets generated for me:

public partial class JetStream : DbMigration
{
  public override void Up()
  {
    AddColumn("dbo.MigratoryBirds", "DependentOnJetStream", c =>
      c.Boolean(nullable: false));
  }
  public override void Down()
  {
    DropColumn("dbo.MigratoryBirds", "DependentOnJetStream");
  }
}

Now this class is part of my project. When I run the test again, where I’ve set up the migrate-­database initializer, the test doesn’t throw an exception. And my profiler shows me that prior to the SELECT being executed, the database table schema is altered to add in the new DependentOnJetStream property.

What I’m not getting with this pattern that I liked about the DropCreateDatabaseAlways initializer is a fresh version of the database for integration tests. To achieve this, I have to execute some raw SQL in the Seed method of the configuration file prior to seeding the database. Or, for the integration tests, I could simply disable initialization altogether and control the database creation explicitly. Eric Hexter wrote a great blog post about this, “Using SQL Compact for Integration Tests with Entity Framework” (bit.ly/1qgh9Ps).

Where MigrateDatabaseToLatestVersion Shines

If you were to compile the project and give it to another developer who hasn’t migrated her own development database, the initializer would trigger the app to look for a migration. The migration will be found because it’s in the project. The initializer will check the database’s migration history table and update the database schema, if necessary.

Considering this in production, not development, the migration class will be compiled into your assembly and deployed as part of the application. When the application is run, it will respond to a MigrateDatabaseToLatestVersion setting (in the appropriate place in your application) and update the database schema accordingly.

So What Happened in the Azure Web Site?

Now that you have a good understanding of how MigrateDatabase­ToLatestVersion works, let’s get back to the conversation with my friend. We left off at: “What about the migrations initializer? That would do it, too.”

He replied that he hadn’t set the migrations initializer anywhere in the code. So now it was a big mystery. The behavior matched that of MigrateDatabaseToLatestVersion exactly. He deployed his app to Azure. When he ran it, the app noticed the change he had made in the model before redeploying and it updated the database schema.

With all of these questions asked and answered, leaving me a bit mystified, I went to my favorite search engine with some useful information in hand and made a discovery.

When you publish a Web app to Azure, there’s a checkbox on the settings page that’s unchecked by default. But that checkbox says “Execute code first migrations (runs on application start).”  Checking this will add the MigrateDatabaseToLatestVersion setting declaratively in the config file.

I e-mailed my friend and showed him a screenshot of the page with that setting and asked, “Look familiar?” Mystery solved. He had created the migrations and updated his development database. So the migrations were compiled into his assembly when he deployed it. And he remembered ticking that checkbox.

So when he ran his Web site for the first time, the initializer called DbMigrator.Update, which compared the list of migrations in the assembly to the list in the MigrationsHistory table and ran any that weren’t present in the table.

Now he recognizes that as a feature, not a mystery.


Julie Lerman is a Microsoft MVP, .NET mentor and consultant who lives in the hills of Vermont. You can find her presenting on data access and other .NET topics at user groups and conferences around the world. She blogs at thedatafarm.com/blog and is the author of “Programming Entity Framework” (2010), as well as a Code First edition (2011) and a DbContext edition (2012), all from O’Reilly Media. Follow her on Twitter at twitter.com/julielerman and see her Pluralsight courses at juliel.me/PS-Videos.

Thanks to the following Microsoft technical expert for reviewing this article: Rowan Miller