Try Not To Reference Your DbContext In Entity Framework Code First Migrations

I recently ran into a problem where a developer was trying to pull down the latest version of the NemeStats codebase (https://github.com/jakejgordon/NemeStats) was getting the below error when running the Entity Framework code first migrations via “update-database”. The error was:

The model backing the ‘NemeStatsDbContext’ context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269).

The most common proposed solution to this error is to add the following line to your Global.asax.cs Application_Start():

Database.SetInitializer<MyContext>(null);

However, in my case I was getting the error because I had a migration that actually referenced my DbContext directly rather than using the Sql method that is available in Entity Framework migrations. The problem with this is that the developer was starting with a fresh database that was on say, version 1 but the most current version of the code corresponded to say, version 15 of the database. When the offending migration runs and references the DbContext directly it is assuming the DbContext has models that were in place when the migration was written. When a developer runs “update-database” with the current version of the models and custom code runs, the models could be wildly out of sync with the code that was in the migration and the above error is thrown. Let’s take a look at the following example to illustrate the problem.

Migration 1

A new Player table is created with an Id and Name column:

public override void Up()
{
    CreateTable(dbo.Player", c => new
    {
        Id = c.Int(nullable: false, identity: true),
        Name = c.String(),
    }).PrimaryKey(t => t.Id);
}

Migration 2

This migration uses the DbContext directly to update the Player table, rather than using Sql(…). This will work fine so long as the models associated with ExampleDbContext never change from this point forward. Not likely!

public override void Up()
        {
            using (ExampleDbContext dbContext = new ExampleDbContext())
            {
                Player playerToUpdate = (from player in dbContext.Players
                                 where player.Name == "Foo"
                                 select player).FirstOrDefault();

                if (playerToUpdate != null)
                {
                    playerToUpdate.Name = "Bar";
                    dbContext.SaveChanges();  
                }
            }
        }

Migration 3

This migration makes a change to the Player model/table by adding another column called DateRegistered. This migration is listed just to demonstrate that the Player model backing the ExampleDbContext will have an extra property in the most current version of the code.

public override void Up()
{
    AddColumn("dbo.Player", "DateRegistered", c => c.DateTime());
}

What Happens When You Run These Migrations With a Fresh Database

The first migration will run just fine and will create the Player table.

The second migration will fail and give the error:

The model backing the ‘ExampleDbContext’ context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269).

The problem is that the current version of the code has a Player model with Id, Name, and DateRegistered. When you first access the ExampleDbContext in Migration 2, the database doesn’t yet have the DateRegistered column (since this is added in Migration 3 which hasn’t run yet). Entity Framework compares the models with the database and realizes that they are not in sync, and throws this error.

Conclusion and How To Avoid This Problem

The short answer is that you should really try to avoid referencing your DbContext directly in a migration as it will eventually cause problems when your model changes.  Whenever you have to pull down the project with a fresh database your migrations will fail when you run update-database. If you need to access or manipulate the database you should use the built-in methods that are on the DbMigration class which all migrations extend. In the example above, rather than updating the player using the DbContext, I should have updated it using the Sql method in my migration as follows:

Sql(“UPDATE Player Set Name = ‘Bar’ WHERE Name = ‘Foo’;”);

There may actually be times when you have a good reason to want to run code and reference your DbContext in a migration, but this is a topic for another post.

Hopefully this helps someone else who runs into this problem!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s