Join Richard Goforth for an in-depth discussion in this video Migrations against an existing database, part of Accessing Existing Databases with Entity Framework Core.
- [Narrator] Migrations are a key feature of Entity Framework. They allow a source controlled, revertible, versioned way to know that the database schema and schema that the code expects line up. I've opened a command line window and navigated to the directory that contains our project. To begin using migrations with our existing database, we'll type dotnet ef migrations add, we'll name the first migration initial, but you can name it anything you like. Now that that's completed, let's open up the project and see what's been added.
We have a new folder named migrations. Within the migrations folder, we have two files. The first file that we'll look at is the context model snapshot. The context model snapshot rolls all of the model definitions, data annotations and conventions into a single complete database definition. This file is regenerated regularly so we shouldn't make any changes to it, but it can be worthwhile to view this file. Since it contains the full definition of our database, we can use it to track down or identify mismatches in our model with the existing database.
Now we'll look at the migration file. When a new migration is added, Entity Framework analyzes the difference between the previous model and current model, automatically populating the migration. Since there are new previous migrations, this migration is trying to create the database from scratch. Since we already have the database, we could empty out the up and down methods of this migration. All right, let's go back to the command line window to run the migration. Dotnet ef database update will run any migrations that have not yet been run on our current database.
Let's go back to the SQL Server Object Explorer to see what's changed in our database. Open up the database and select tables. Under tables, you will see a new table, __EFMigrationsHistory. Let's right click and view data. We'll see it's a very simple table. It has two bits of information, the product version of Entity Framework and the migration ID. You'll notice the migration ID is the same as our filename. This table tracks migrations that are currently applied to our database.
This allows Entity Framework to migrate databases at any point on the migration history path. Now that we have an initial migration, we can make a change and push that change to the database. We'll start by opening the models folder and going to our context. Scroll to the customer entity definition. We've decided that the email field is too short and we want to change the type from having a 50 character limit to a 200 character limit. We'll change that here in the column type and save our changes.
With the changes saved, we'll navigate back to the command line window. Here, we'll add another migration, dotnet ef migrations add, we'll name this one email length increase. Let's view this migration in our code editor. You'll see here we have a reload notification. Since the snapshot file has been updated by the migrations command, we want to reload it from disk. Let's view the new migration email length increase under the migrations folder.
Here in the up method, you can see we've altered the column and changed the type to a length of 200. You'll also note in the down method, the column is altered back to its original state. This means I can migrate a database back to its previous state. This can be really useful when debugging an older version of the code. We can ensure that the database schema matches what's currently in production for this application. We've created the migration, but now we've realized that we want the field to be 250 characters instead of 200.
Let's go back to our context and make that change. We'll make that change and save the file. I'll delete this migration file and recreate it through the command line. I'll press up to restore the previous command. Let's go look at our new migration file. We'll reload the snapshot from disk. Now that we can see the new field length is 250, let's apply this migration to the database. Back in the command line window, we'll run dotnet ef database update again.
Let's have one more look at the database in the SQL Server Object Explorer. We can navigate to the customer table, drop down to column definition and see that the email field is now 250 characters long. We've now seen the basic operations that we can do with migrations. If we want to undo this change, we can run dotnet ef database update and add the name of the migration we would like the database to be at. In this case, we'll say initial to go back to the first migration.
The migration is still in place, but now the database is back at a 50 character length for the email. We can put the email length back in place by running dotnet ef database update again without a migration name. If we need to make a change to an applied migration, we have to migrate the database backwards, change the migration and then migrate the database forward again. We've now seen the basic operations of migrations. The one thing we can't do here is mix using migrations and updating the database outside of our application.
If we update the database separately, the migrations could fail. For example, dropping a column that's already been dropped. If you change existing migrations, you lose the ability to move back and forth and most of the value of using migrations in the first place. If your database is going to be updated outside of this application, it's better to go with the database first approach.
- Setting up your project
- Connecting to a legacy database
- Scaffolding an initial model and context
- Improving the model
- Updating properties and indexes
- Adding concurrency tokens and timestamps
- Creating complex relationships
- Working with non-Microsoft databases such as SQLite and PostgreSQL