Monday, 23 December 2013

Code First Migration

Let say we are using Entity Framework Code First for our project and have a class below:
public class Student
   public int StudentId { get; set; }
   public string Name { get; set; }
When we use the database context for the first time, the database will be created with a table called __MigrationHistory.

The table has one record initially.

To enable the migration feature, type enable-migrations on Package Manager Console. Some messages will be displayed when the command has finished running.
PM> enable-migrations
Checking if the context targets an existing database...
Detected database created with a database initializer. Scaffolded migration '201312050353336_InitialCreate' corresponding to existing database. To use an automatic migration instead, delete the Migrations folder and re-run Enable-Migrations specifying the -EnableAutomaticMigrations parameter.
Code First Migrations enabled for project CodeFirstMigrationTest.
A folder called 'Migrations' with two files are created.

[timestamp]_InitialCreate.cs is created because the database has already exists when the first time we access the database context. If the database was still empty then only Configuration.cs file would be added.

There are two main commands for the migration feature:
- add-migration - add migration codes in the code layer (under 'Migrations' folder)
- update-database - update the database according to the migration codes written in the code layer

Now let's try to change our model to add a new property:
. . .
public DateTime DOB { get; set; }
. . .
Then run add-migration command to add the change:
PM> add-migration addDOB
Scaffolding migration 'addDOB'.
The Designer Code for this migration file includes a snapshot of your current Code First model. This snapshot is used to calculate the changes to your model when you scaffold the next migration. If you make additional changes to your model that you want to include in this migration, then you can re-scaffold it by running 'Add-Migration addDOB' again.
[timestamp]_addDOB.cs file is created.

Now try update-database command to apply the changes to the database:
PM> update-database
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
Applying explicit migrations: [201312081946270_addDOB].
Applying explicit migration: 201312081946270_addDOB.
Running Seed method.

Then check __MigrationHistory table again. As we can see, a new record is created in the table with Id value the same as the name of the newly generated file.

If necessary, we could customise the codes in the file generated by the add-migration command.

update-database command also has a few parameters that could be useful. We will see briefly TargetMigration, SourceMigration and Script parameters.

To upgrade/downgrade the database to a specific state, use -TargetMigration parameter. For example:
Update-Database –TargetMigration: addDOB
To roll back to empty database, use $InitialDatabase:
Update-Database –TargetMigration: $InitialDatabase

To get the changes in script only without applying those to database, use -Script parameter:
Update-Database -Script -SourceMigration: [initialState] -TargetMigration: [targetState]
If -SourceMigration is not specified then it will use the current database state. If -TargetMigration is not specified then the latest state will be assumed. For example, the command below will generate all migration scripts from empty database up to the addDOB migration state.
Update-Database -Script -SourceMigration: $InitialDatabase -TargetMigration: addDOB

Starting from EF6, we could use the generated scripts to update from any previous state to the one specified as the target. The scripts have logic to check the states based on entries in __MigrationsHistory table.


No comments: