Tuesday, 24 December 2013

Enabling Automatic Code First Migration

This post is describing how to set automatic Entity Framework Code Fist migration, for the manual migration please see my previous post.

Automatic Code First migration feature is useful during development phase when database has not gone into production environment yet.

If you haven't got an EF migration Configuration.cs file then you can run this command on Package Manager Console:
Enable-Migrations –EnableAutomaticMigrations
This will add a folder called 'Migrations' in the project and a file called Configuration.cs with this setting in the constructor method:
AutomaticMigrationsEnabled = true;

If you have already got the file, make sure that AutomaticMigrationsEnabled property setting is set to true in the constructor.

Secondly, ensure that MigrateDatabaseToLatestVersion initialisation option is set on the project startup file (for example; inside global.asax)
Database.SetInitializer(new MigrateDatabaseToLatestVersion<DatabaseContext, Configuration>());
DatabaseContext: your database context class name
Configuration: this is the Configuration file discussed earlier. You would need to make the class to be public if you put the initialiser inside other project.

Also if we want the automatic migration to allow data loss (for example; allowing column to be removed) then AutomaticMigrationDataLossAllowed property would need to be set to true.

So the constructor will have these settings:
public Configuration()
    AutomaticMigrationsEnabled = true;
    AutomaticMigrationDataLossAllowed = true;

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.