Overcoming EF Core Migration Conflicts

Interesting times!!! We've been having issues with EF Core migrations for while now and we're trying overcome them as we go, trying to put a process in place so we have less conflicts as possible. But still, once in a while, people forget to follow the process or just choose not to do so and then we have issues. Let's see what we did about.

Our process

  1. I'm just about to submit a pull request with a database migration inside
  2. Pull latest from the target branch you're creating the pull request to. In our case git pull origin dev. Resolve any conflicts, if there's any pending migrations coming from the remote branch, make sure you delete your branch and recreate it.
  3. Shout out!!! Tell everyone in the team saying that this pull request has a migraiton inside. Either using Slack or any other effective mean.
  4. If anyone is about to submit a pull request with a database migration, he/she will wait until the pull request is completed.

This process doesn't sound complicated at all, but, trust me, people do forget to follow this process and you end up with migration conflicts.

So I went and asked the Magic Unicorns (@efmagicunicorns) on Twitter (here's the thread), and even though they didn't say anything different to what we're doing, it was quite reassuring to know that our process is not really wrong.

Resolving conflicts

Might by obvious, but just to mention here:

  1. Remove migrations up to the point of the conflict: dotnet ef migrations remove
  2. If the EF commands are not working to rollback because of the conflict, you can copy the content of the BuildTargetModel method inside the *.Designer.cs file from the migration you want to rollback and replace the whole content of the BuildModel method in the *ContextSnapshot.
  3. Create a new migration dotnet ef migrations add [NAME OF MIGRATION]

Can we do anything to avoid conflicts?

Well, Jernej Kavka came with a very nice solution (here's the post), to treat the DbContextModelSnapshot file as binary from a git perpective, this way, when a dev has a conflict in the database they will be forced to recreate the migration to remove the conflict. And that's a quite nice solution.

What did we learn?

We learn from challenges and although this was a quite painful one, we did learn a few things.

  • The Migrations/*.Designer.cs files are used in design time only (I know it's obvious). And they're really only used when you want to rollback a migration dotnet ef migrations remove.
  • You can remove all Migrations/*.Designer.cs if you want to and it's not going to impact any future migrations, but if you try to remove a migration, it will jump to the last *.Desiner.cs file it can find. For example, we tried removing the 2 last *.Designer.cs files and when running dotnet ef migratios remove, it actually removed the 3rd last migration.
  • Breaking the migration stream doesn't really affect anything when applying migrations.
  • EF does NOT use the Migrations/*.Designer.cs files to apply migrations.

TIP: When creating a new migration, just make sure the generated migration actually reflects the changes you've made. You will be able to spot conflicts there. I've actually seen people just triggering dotnet ef migrations add [WHATEVER] and not checking the migratoin itself, you'd be surprised.

And that's it, hope I can save someone else's time. It really did my head.

Have you ever had database migration issues and care to share? I'd love to hear.

Cheers.