Entity Framework Code First Migrations in Teams

comments

Migrating to a Code-First or Model-First approach to database development can be very liberating. At the end of the day your database is just a way of storing state, so getting away from the implementation details can really help speed up development and allow you to focus your efforts. Code First’s awesomeness aside, when you try and implement this kind of paradigm shift within a team you unlock a different set of problems. Here are two potential ways to alleviate some of the headaches.

Entity Framework has had a Code First approach for a little over 2 years. In that time if you’ve been surfing the net and read all the posts and reviews covering peoples experiences, you’ll come away with the view that it has become quite popular with developers everywhere. One thing you don’t see many people talking about however is how it works to use it in teams of more than one. It isn’t suited to all projects that is clear, but when used correctly it can really speed up development.

Implementation Details – Removed or Replaced?

Entity Framework Code First Migrations force you to think about your database model differently. Instead of thinking tables and columns, you simply think about your domain objects as they are - the rest will “sort itself out".

image

The “old school” database first approach

namespace Blog.Data
{
    public class BlogContext : DbContext
    {
        public ICollection<Author> Authors { get; set; }
        public ICollection<Blog> Blogs { get; set; }
        public ICollection<Category> Categories { get; set; }
    }
    public class Author
    {
        public string Name { get; set; }
        public virtual ICollection<Blog> Blogs { get; set; }
    }
    public class Blog
    {
        public string Title { get; set; }
        public string Content { get; set; }
        public string Url { get; set; }
        public virtual Author Author { get; set; }
        public virtual Category Category{ get; set; }
    }
    public class Category
    {
        public string Name { get; set; }
    }
}

The “new” sexiness/“Domain model is all I care for” approach

As you can see from the second approach allows you to simply stop caring for how the data is even stored, and just concentrate on your app and the model of your data as classes and properties. You create your domain objects and Entity Framework takes care of the rest. Like a lot of the additions to .Net over the past few years, this is not new, but rather borrowed from other frameworks like Ruby On Rails. 

What it’s likes when working alone

When working with Code First Migrations, your work flow reeks of awesome simplicity:

image

 

This is a dream to work with, and when you go to push between staging and production the roll up is all taken care of for you, and you simply get on with better things. This is the magic of Code First Migrations! 

The problems only begin to appear when you have more than one developer working with in a team. This is even more of a problem if your team aren’t within close enough proximity or contact to talk all the time as they can’t communicate of segregate who is updating the domain model and migrations at a time. In fact if you are using anything more than a rudimentary approach to source control this is next to impossible as you’ll always be merging codebases that started in a shared previous state.

This then looks more like:

image

Did I mention that Code First Migrations does some magic behind the scenes that makes each migration aware of its “previous state” making it next to impossible to “merge” in the way you would have previously?

When these migrations are then played out against your database, developer B (or whoever checks in last) and their migrations always fail as his/her migration comes from a parent domain model state that no longer exists, as the current version of the model has changed since checkout or branch.

Unlike Ruby on Rails migrations, the code migrations generated by the PowerShell helper in EF Code First add an additional field that make them database state aware.

We’ve replaced one set of implementation details with another.

Magical voodoo in each of the migrations:

string IMigrationMetadata.Target
{
    get { return "XiSR4t76Fv...G2vKGQAAA=="; }
}

This field contains an encoded string representing the EDMX XML model of the domain model at time of migration. Entity Framework checks your database before applying every migration to ensure that the database is in the state that it thinks it was from the previous migration classes Target property. This then stops migrations from occurring on a database that has changed since checkout, to avoid any data loss or confusion over elements that may have changed in both migrations. It then stores a copy of this serialised model in the system table __MigrationHistory.

Code First Migrations in a Team

The following two methods are process solutions to this problem. They aren’t perfect, but they do seem to make the workflow a little less frustrating at times if everyone in your team is aware of the steps and follows them – very similar to some of the workflows for branching and rebasing used in Git or Mercurial these days, after a while these steps can second nature.

Both methods rely on local development databases being used by each developer separately. This approach therefore also requires seeding any testing data or 3rd party data.

Action Plan A - Automatic Migrations

The first method is based around the use of Automatic migrations while working on your local changes, and then pulling your repo down, merging any domain model changes and creating a new manual migration.

This method works like:

  1. Pull down the latest Domain Model into a branch.
  2. Turn on Automatic Migrations.
  3. Develop, Develop, Develop.
  4. Blow away your Development Database (and with it your __MigrationHistory table, and it’s state)
  5. Turn automatic migrations off
  6. Pull the latest trunk/master Domain Model from your Source Control repo up into your branch.
  7. Merge the latest Domain Model with your local changes.
  8. Add a new migration of “the difference” between the repo and your domain model.
  9. Test a migration “up” on your local DB.
  10. Merge your branch back into your mainline.

Action Plan B - Manual Migrations

This approach is quite similar but works to allow local code first migrations during any given modification period.

This method looks like:

  1. Pull down the latest Domain Model into a branch.
  2. Develop, Develop, Develop - adding as many migrations along the way.
  3. Blow away your local database (and with it your __MigrationHistory table, and it’s state)
  4. Delete all of your local migrations.
  5. Pull the latest trunk/master Domain Model from your Source Control repo up into your branch.
  6. Merge the latest Domain Model with your local changes.
  7. Add single migration of “the difference” between the repo and your domain model.
  8. Test a migration “up” on your local DB.
  9. Merge your branch back into your mainline.

Summary

The main differences between these two workflows is that the first method saves you a little bit of time between small domain model changes. This can be really handy if you have remote teams where some members are working together in the same room on the same branch/head, as it reduces a bit of friction while they are working. This also tries to bring the problem back to being just what it should be: a code merging one with your domain classes. 

I am still a big fan of Code First Migrations, and when you work with others in a team that uses them you can make some huge performance gains if you take the time to make your human processes play nicely with them. With a bit of practice the pay off is definitely worth it.