As usual in the recipe section we will look at the following:
- The problem to solve
- Why would you do this
- What do we actually do with this &
How are we going to do it
- Advanced features
In this recipe we are going to look at the already prepared database from the other recipe posts and demonstrate how to add a property, update the database so that the changes are incorporated and after that reverting the changes by removing the property.
We will take a look at the two possible cases where you want to revert a migration. A simple one and one that is more complex. We also will look into the consequences for both cases.
Basically there are two scenarios:
- One where the migration was not ran against the database
- A second one where the migration already changed the database.
The first one can be easily reverted and has no repurcussions and is safe to do.
In the second case we will see that it is also quite easy to do in a way, but needs a little more work and attention to do. Especially if there is already data.
As mentioned in every recipe in the topic about ef core migrations, software is in a constant proces of change because nothing is carved into stone.
Therefore our data schema and our entities may constantly change. For this reason we want to be able to add something to our data but also want to be able to remove something if anything went wrong.
To do so we explore how to revert made changes with ef core and the migrations they provide.
When we want to update an existing database, created a migration but recognize that we made a mistake as mentioned above we have two ways to handle this.
In essence this means we need to “unapply” a migration.
1.) Case one: Not applied to the database yet
The first case is the easy one.
We created a migration from the command line and have the files in place.
But we fortunately did neither run the command:
dotnet ef database update
Nor did we start the application with context.Database.Migrate() in place.
As a result of no changes applied to the database, we then can simply run the unapply command like so:
dotnet ef migrations remove
(by default it removes the latest created migration which will be determined by the date of the migration).
Be aware, that you still need to change the given model by yourself.
If you added a property for example you still need to remove it from the entity (this holds also true for the second case).
Because else you would get this change with the next migration again.
2.) Case two: Already applied the migration to the database
The second case is a little more complicated.
It has all the other combinations: You either did run context.Database.Migrate() or the command
dotnet ef database update.
So how do we revert then?
First we check the help that is provided by the dotnet ef database command. See the output on the image listed below.
We can see here, that we can specify the migrations until ef core should apply to the database.
To revert an erroneous migration we can simply run the command with the migration as parameter that came before the erroneus migration.
This will run all the down methods on the database until the specified migration target is reached.
In our example app this would look like this:
dotnet ef database update \
-c TodoItemContext <MigrationBeforeTheErroneousOne>
(If we use as a parameter the ‘0’ isntead of the migrationName, all migrations will be reverted.)
After that we want to run
dotnet ef migrations remove
(defaults to the latest one)
This then totally removes the erroneous migration. Also make sure to have this order of commands, else the down method is lost!!!!!
As with the other case, you need to change the Entities by hand.
To revert the database like this has one big drawback though: You loose the migration files (they will be in the changeset, but it is better to have the files in place for reference in an production environment).
To avoid loosing the trail of migrations you can also create another migration where you first update the erroneous entities and create a migration based on this, apply it to the database and have some further control over the history.
This also makes it much easier to handle some already supplied data in the database.
Even though it is still in the source control history, it might be a good idea in an production environment to see what changed. This is especially useful for something like microservice systems where multiple versions are run in parallel.
- Especially in an application that already has some data accumulated to the to be reverted entity/property you need to think about handling those data
- Absolutely try to avoid running this migrations on production systems (sooner or later this will probably happen as we all know how pressing product managers and customer support teams can be 😉 )
- It is becoming more interesting when you have multiple contexts, SQL default values and other things to be considered. We will look into this in future recipes and posts (probably)