Entity Framework Code First Migrations in a Team Environment

The managing of a database schema has seen several advances over the years in the .NET stack. Circa 2010, Visual Studio began shipping with a new Database Project, and some SKUs included data compare tools, which helped compare data schema and the data itself. Around the same time, Entity Framework was launched, at first only offering support in  Model and Database First approaches, it was soon offered with the now, super popular, Code First approach.

The introduction of Code First was in reaction to people who wanted to keep their time in writing code and out of a database designer. So if we’re going to stay out of the database designer, how do we manage our database’s schema? Enter Migrations.  Code First Migrations can analyze your model and automatically create schema update files to get your database updated with your latest model changes. When I started using Migrations, I was in love. It was seriously time saving and super easy to use.

Soon enough, after touting, and bragging about how I found the new hotness, I introduced migrations on a project that I was working with a few other people on. The first week went…well…not good. I really thought this whole thing was gearing up for me to end up with some serious egg on my face.

The Pain, Oh The Pain

So, in order to understand why there was pain, we first need to understand how migrations work. Before doing any deep dives, I made assumptions. My main assumption that when I started with code first was that with  the ‘Add-Migration’ command, the magic going on was that the little minions inside were going out to my database and making notes about what’s different between the database and my code first model. I mean, this is logical, right, this is how we track schema changes using the Schema Compare tool in the past. Well, wrong-o. Code first doesn’t care about your database at all.

In reality, migrations are doing their comparisons against the last known state of the model. It does that this by making use of a snapshot file. You see, whenever you issue an ‘Add-Migration <some migration>’ command, migrations creates a snapshot of your entire model. So the next time you issue an ‘Add Migration <some other migration>’, migrations compares the current state of the model to the snap shot that was created in ‘some migration’. Seeing the problem yet?

So this all works fine and dandy for you. So now lets imagine that we have two developers Sarah and Roger. Sarah does some work, creates a migration, SarahMigration1, and checks in. Roger, gets latest, and sees Sarah’s migration, SarahMigration1. He begins doing some work and creates a migration of his own, RogerMigration1. So behind the scenes, migrations compares Roger’s changes against the snap shot and spits out a migration file. Sweet. But Roger isn’t done working and doesn’t check in his changes yet. Meanwhile, Sarah needs to create another migration, so she issues an ‘Add Migration SarahMigration2’ command.  So what happens? Migrations doesn’t know about RogerMigrationOne, or the snapshot that was created along with it, so migrations compares Sarah’s current model against the only snapshot it knows about, which is SarahMigration1. So a migration file is created that looks good, since Sarah knows nothing about Roger’s changes, her new migration looks and seems right. What what happened behind the scenes is what’s going to cause some problems. The snapshot that was created in Sarah’s last command, doesn’t include Rogers’s changes. So Sarah checks in and Roger gets latest. Since migrations lists migration by date, he will see SarahMigration1, RogerMigration1, and SarachMigration2.  Ok…seems ok. Oh, but it’s so not. When Roger goes to create his second migration, migrations is going to compare his current model against the latest snap shot, SarahMigration2, but the snapshot in SarahMigration2 knows nothing about RogerMigrationOne changes, so migrations is going to generate all of Roger’s changes, including the changes that are already defined in RogerMigrationOne.  Whoops.

The Solution

I like to call this the, ‘Oww, My Toes’ scenario. So the obvious solution might be, just delete RogerMigration1. While that might work in some scenarios, if you’ve updated your database, you’re going to be in a world of hurt if you do that…so don’t do that.

To fix this scenario, you have 2 options:

Option One: Generate A Blank Migration
  1. Write all of your pending model changes to a migration and update your database.
  2. Get latest from source control
  3. Issue an ‘Add-Migration <some name> -IgnoreChanges’ command

This method will result in a blank migration file being added to your codebase, but this solution is quick and easy, so the tradeoff of having blank files may be worth it. Note that this option will not work for you if you have already gotten latest before writing your pending model changes to a migration, so you may want to get into the habit of writing your changes to a migration before getting latest.

Option Two: Regenerate the Snapshot
  1. Find the migration before the one that matches your current database status.
  2. Issue command ‘Update-Database – TargetMigration [migrationbeforecurrent]’
  3. This will revert your database ‘back to good’ if you will.
  4. At this point, you can delete your migration that is in between the other two as well as the latest migration that had the duplicate migration code.
  5. Issue Command ‘Add-Migration MyNewMigration’
  6. This will create a new migration that
  7. Issue Command ‘Update-Database

This should bring the database base back to good and inline with the migrations files, as well as creating a new snapshot of the database that matches the current code first model. Note that this option only works if the latest migration exists in your local workspace only. It cannot have been committed to source control.

Whew.

Best Practices For Teams Using Migrations

  1. Turn off Automatic Migrations – This isn’t just for teams, this is for pretty much anyone using migrations. Automatic migrations takes all control away from the developer on how the database is migrated. You should be in control of the migration files to avoid, ‘It just deleted all my data scenarios’ (Yes, it will do this. Be extra sure you have automatic migration off for anything in Production)
  2. Get latest often – Always having the latest helps to reduce the number of times this scenario occurs.
  3. Check in often – On the contrary, be a good team member by getting new migration checked in as soon as possible.
  4. Designate a migration master – This certainly isn’t going to work for all teams, and it comes with some risk that the migration master becomes a bottle neck for the whole team. But basically, the other developers make changes to the context model, but the actual migration files are always created by one person, that person is always guaranteed to have the correct snapshot of the model if they are the only one creating migration files. This is the only option to completely eliminate the ‘Oww, My Toes’ scenario.

Understanding the Problem is the Hardest Part of Any Software Project

confusion-311388_640It doesn’t matter what piece of software you’re building, the key to success lies in having a deep understanding  of the problem you are aiming to solve.  It’s so common to for a project to get well underway before the problem domain is fully understood. It’s a natural thing to happen.

When a client comes to you with an idea for software, we usually begin by talking about their idea in terms of our technical minds. When they’re explaining whatever requirements they’ve put together, our wheels start spinning with how we’re going to architect our solution, or what how we’re going to design this feature or that. Before we know it, we fire up our IDE of choice and start hammering out our solution.

Before long, we begin to run into scenarios that we’re not sure of what the right answer is. At this point, we are left with a choice: get the answers to the questions we have to better understand the problem, or make assumptions about what is probably the right answer, and keep being productive. The misunderstanding is that breaking stride to get a better understanding of the problem is not productive. When we do this, we’ve already set ourselves up to fail. It doesn’t necessarily mean you are going to fail, but there will be pain. As we jump to implementation, we are giving up great opportunities to dive deep into the problem domain. By taking the time to dive into the problem domain, not only are we still productive, but we’re actually more productive in the long run as we will inevitably be more accurate in our solution, requiring much less rework.

So how do we dive deep into understanding the problem domain? The short answer is to ask questions. But it’s not just asking questions, it’s asking the right questions.

The end user is your greatest asset. The key to understanding the problem is to understand how the end user works and how the product fits into how they work. Get the end user talking and keep them talking by asking “What else?” and “Tell me more about _____”.

Understand the business domain. Your technical domain should match your user’s business domain. When you begin introducing technical terms to a user’s vocabulary, you are attempting to change the way they work. Instead you should be aiming to avoid technical terms that have no place in the business domain.

Understanding the problem domain is both hardest and most important aspect to developing any piece of software. I like to never assume that I know enough about the business domain to make assumptions about it. It’s always a better use of time to get the answers to questions as they come up than making assumptions and continuing down the wrong path.

SlowCheetah for Configuration Transforms for Windows Apps

1_Configuration Manger

UPDATE:  The creator of SlowCheetah has announced that he will no longer be supporting SlowCheetah. His intent was for Microsoft to implement this solution into Visual Studio out of the box. Unfortunately, that has not yet happened.  If you would … [Continue reading]

Migrating a Project from Database First to Code First

generate_views

Overview So you just pushed you application to production and used Microsoft's new shiny ORM. It's 2008 and you're on the bleeding edge of .NET technology by implementing Entity Framework. Your EDMX paired with your database project keeps your … [Continue reading]

OpsHub and Polaris Solutions Announce Partnership to Drive Collaboration and Efficiency of Teams in the Software Development Lifecycle

OpsHub and Polaris Solutions announce partnership offering software development organizations a comprehensive Team Foundation Server (TFS) based solution for quick and easy adoption of Team Foundation Server (TFS), driving collaboration and … [Continue reading]

Polaris is a Platinum Sponsorship for Chicago Code Camp 2014

Polaris has just signed on as a Platinum Sponsor for this year’s Chicago Code Camp at the College of Lake County campus on April 26th, 2014. Chicago Code Camp is a free, community-driven developer conference. Over 200 attendees and 17 sponsors … [Continue reading]

Polaris Solutions is a Gold Sponsor for Agile Gravy STL 2014

We’re proud to announce that we just signed on as a Gold sponsor for the first annual Agile Gravy St. Louis conference – a rich & savory 1-day Agile conference experience that’s worth soaking up every last drop. Early bird registration is … [Continue reading]

I’m not a phony, and neither are you

Awhile back I read a blog post titled, "I'm a Phony, Are you?" by Scott Hanselman. If you're reading this blog, you are probably well aware of who Scott Hanselman is. But, for those who are unfamiliar, Scott is basically the definition of Rock Star … [Continue reading]

Polaris is a Platinum Sponsor of St. Louis Days of .NET

Clint Polaris Booth STLDODN

For all of our friends in the St. Louis, MO area.  St. Louis Days of .NET is now under way. Polaris is proud to be a platinum sponsor for the event and will be hosting a booth, which from the image above, you can see Clint working furiously to set … [Continue reading]