Changing the Namespace With Entity Framework 6.0 Code First Databases

Sometimes a refactoring of your project includes changing the namespaces used throughout your project. If you’re using Entity Framework 6.0, this type of change can have an impact on EF’s ability to detect the current status of your namespace. This article helps you to mitigate any conflicts and allows your migrations to stand as-are.

I cover a bit of background, but you can jump to the end to see two or three possible fixes.

Also, sending a thanks out to my good friend David Paquette for the review on this post.

My Beef With Existing Fixes

If you change namespaces and run into problems, you might see an error similar to the following:

An exception of type ‘System.Data.SqlClient.SqlException’ occurred in EntityFramework.dll but was not handled in user code

Additional information: There is already an object named ‘AspNetRoles’ in the database.

I’m not sure I would call this misleading, but it certainly doesn’t explain the problem in the clearest of terms. Here’s what I would prefer to see, particularly in the Additional Information section of the error message:

Additional information: The namespace for the Entity Framework migration does not have any corresponding migrations in the target database. It is possible that your connection string is not configured correctly, that you are attempting to update a database that was created without migrations enabled, or that your namespace for your configuration class has been modified. Query the migrations table on database *database_name* to review current migration state.

Sure, it’s verbose, but it lets you in on what might be happening.

Specifically, migrations are tracked by ContextKey in the __MigrationHistory table and the key includes namespace information. When your namespace changes, you also need to update the records in the DB that correspond to migrations that have already been executed.

My beef with existing fixes? Most of the time when you see similar errors come up the answer seems to ignore the fact that people might be using this stuff in production. Namely, the fix tends to be “drop your database and let the Framework rebuild it”, which, sure, I mean, it solves the problem. It’s just not good for business.

Behind the Scenes

For each change to your database tracked with with a migration, a hash representing your model is computed and stored in order to detect the next set of changes that occur. As you execute the migration, the hash is added, along with the MigrationId and ContextKey to the migrations table.

When you attempt to access your data through the DbContext and you’re using, for example, an initializer such as MigrateDatabaseToLatestVersion, the Framework will attempt to play catch-up and make sure the database reflects the current model in your application. To do this, it queries the database to see where the database thinks it’s at, and it uses both reflection over and information from your configuration and context classes. You can see the queries that run if you capture the chatter with SQL Profiler:

image

And if you drill into the details you’ll see something like the following as the Framework tries to figure out where you’re at:

image

I’ve dashed out my namespace as this was work for a client, but you can see the root of the problem here. The Configuration class is in the Root_Namespace.Migrations namespace; if you move the class to a new namespace, this query is modified to reflect it, but previous migrations stored in the database are not.

Your configuration is automatically created for you when you enable migrations; it’s a class that exists in a namespace which is based on the default namespace of your project. Root_Namespace.Migrations.Congifuration is also the value that is written to the migrations table as the value for ContextKey.

That is our vector to correct the problem.

Building Out The Fix

The first and easiest approach is one that works locally, and could meet your needs if you have access to all affected databases. All you have to do is execute a modified version of the SQL script below:

UPDATE [dbo].[__MigrationHistory] 
   SET [ContextKey] = 'New_Namespace.Migrations.Configuration'
 WHERE [ContextKey] = 'Old_Namespace.Migrations.Configuration'

You should be golden at that point, however, this won’t work if you’re doing continuous integration with a team of developers, or if you have a continuous deployment strategy in place. For that, the solution lies in adding the following code to your database Configuration constructor class:

public Configuration()
{
    AutomaticMigrationsEnabled = false;
    this.ContextKey = "Old_Namespace.Migrations.Configuration";
}

This strategy is more durable and will help prevent any of your teammates (or production servers) from running into the same issue. Of course, this keeps your old namespace hanging around in your migrations table, but it does the trick.

A potentially more elegant solution would be to create a database initializer that takes the old and new namespace into account and corrects the migrations table if necessary. This could end up being considerably more work, so you’d have to evaluate if it makes sense for your project and timeline. You can reference an example implementation here:

MigrateDatabaseToLatestVersion Source on CodePlex

Cheers, and happy coding!

4 thoughts on “Changing the Namespace With Entity Framework 6.0 Code First Databases

  1. Pingback: Decaying Code | Community Update 2014-02-25 – #EntityFramework with @CanadianJames and some #ElasticSearch

  2. Pingback: Friday Five - February 28, 2014 - The Microsoft MVP Award Program Blog - Site Home - MSDN Blogs

  3. Solomon

    Thank you a Trillion!!!!!!!!!!!!!!!!!!!!!!!! you have saved me days of head scratching. all other solutions i found suggested deleting the database. Once again Thank you!!!!!!! Mister James. God Bless you

    Reply
  4. Solomon

    Mister James, now my app runs but when i query the collection that had the “there is already an object named ‘Children’ in the database”. i get an empty result. I opened the database and can actually see my records.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>