6

I have a service which uses EF Core runtime migrations on startup:

var migrator = dbContext.Database.GetService<IMigrator>();
await migrator.MigrateAsync("targetMigration", cancellationToken);

To generate the migrations I first update the DbContext class, then perform "dotnet ef migrations add" to generate the migration code.

It may happen that a deployed upgrade will be automatically rolled back to the previous version after a migration has occurred. For example if health checks or tests fail. In this case I want the previous version of the application to be able to automatically roll back the migration. I know MigrateAsync can revert migrations, but in my current workflow the migration code will not be in the previous version of the code, so I am not sure whether it will be able to revert the migration.

I can think of a workflow like:

  1. Change DbContext and run "dotnet ef add migration" to generate the migration code

  2. Revert the DbContext change and deploy the application so that the code for migration 'n' exists, but the target migration in MigrateAsync and the version of the DbContext is 'n-1'

  3. Re-apply the DbContext change, change MigrateAsync to target migration 'n', and deploy the application

But this seems awkward and I am not sure whether it is necessary, and whether it would definitely work.

What is a good strategy for deploying code first runtime migrations using EF Core such that if the previous version is deployed, the migration can be automatically rolled back?

1 Answers1

2

From what I know, EF does not have anything prepared for you case, it is really hard to make migrations back and forth in prod, also, you must consider that many migrations can create data loss.

First you need to create a process when a change must be tested very well, when the change gets to production you should be 99% sure that there wont be rollbacks in prod.

As you say, you would need the last version of the code, if not, EF wont know what "down" should do.

In our current system, we analyse each migration, if is a new table or something simple, we just run the migration from the CI. If it is something more complex, or we need more complex movements (table modifications with millions of rows), we just do it by hand, so we can send data to temp tables, fill empty data or work with special functions we just generate the script and work with it.

dotnet ef migrations script 20190725054716_Add_new_tables

It is a really hard problem, Java and JPA shares the same problem to generate a history.

These migrations generators are great for development, but hard for production, changing environments, specially when you need to go back and forth like you, another option is to use other tools to handle the migrations that are better prepared for this scenario, like liquibase

Another idea can be found here:

I ended up creating a custom tool that executed migrations intelligently and automatically determined which model (context) assembly to use for the migration.

rekiem87
  • 1,565
  • 18
  • 33
  • Thank you for your answer. In my case the upgrades are done in a rolling fashion for different services and partitions, all with their own databases, so doing the migration using the deployed code seems necessary. – Matthew Hostetler Jun 19 '20 at 18:32