It’s a good practice to always test your EF migration code when you create a new migration, especially if you are manually tweaking the Up()
or Down()
code. If that code doesn’t apply the changes properly it could put the database in a bad state and break migrations if you try to run it again. I did this once by accident when I first started working with migrations in EF 4 and it was a pain to fix. Since then I’ve been pretty paranoid about making sure the full migration path is valid. To do that, whenever I add a migration, I always:
- Update the database to the latest migration.
- Rollback all the way to the very first migration.
- Update to the latest migration again.
If you can complete those steps without causing any errors then you know the migration path is in a good state. If not, you’ve got some fixing to do.
It’s easy to run this test in Visual Studio using the EF PowerShell commands in Package Manager Console. Run them in this order:
Update-Database | |
Update-Database –Migration 0 | |
Update-Database |
You’ll know right away if something is wrong.
Testing via PowerShell before committing your new migration is good. Unfortunately ~~developers are forgetful~~ humans are unreliable and chances are somebody on your team will forget this step at some point. It would be better if we could validate the migrations as part of our CI build. The EF Core PowerShell module doesn’t work outside of Visual Studio (I tried) so we need another way to run these steps, preferably using a test runner framework. Fortunately there is a way!
Updating the database to the latest migration is simple. You just call the dbContext.Database.Migrate()
method.
var dbContext = new MyDbContext(); | |
// Update to latest migration | |
dbContext.Database.Migrate(); |
Rolling back to the first migration is a little more difficult. The only way to do it is to use this low-level IMigrator
interface. If you look at the source code of the implementation of this interface is explicitly labeled as not being part of EF Core’s public API and shouldn’t be called directly. I put in a feature request asking for this functionality to be exposed but my guess is it won’t ever be. Use at your own risk and know that this might not work in future releases of EF Core.
// Roll back all migrations. NOTE: This is not part of EF Core’s public API. Use at your own risk. | |
var migrator = dbContext.GetInfrastructure().GetRequiredService<IMigrator>(); | |
migrator.Migrate(Migration.InitialDatabase); |
Here’s the full code. You can put this inside of a test and run it as part of your normal CI process and get instant feedback on whether or not your migrations are valid.
var dbContext = new MyDbContext(); | |
// Update to latest migration | |
dbContext.Database.Migrate(); | |
// Roll back all migrations. NOTE: This is not part of EF Core’s public API. Use at your own risk. | |
var migrator = dbContext.GetInfrastructure().GetRequiredService<IMigrator>(); | |
migrator.Migrate(Migration.InitialDatabase); | |
// Update back to the latest migration | |
dbContext.Database.Migrate(); |
Right now this test would have to connect to a live database. I’m experimenting with a way to run it entirely in memory. Stay tuned for that.