EF Core Migrations

Summary: in this tutorial, you’ll learn about how to use the EF Core migrations to synchronize the changes of models to the database.

EF Core Migration flow

In practice, the database schema will evolve with new requirements. For example, you may want to create a new table or modify an existing table by adding or removing columns.

Typically, you have to do all of these tasks manually by executing SQL commands in the database.

Fortunately, the EF Core migration feature makes this flow easier by allowing you to make the changes in the models, generate the script based on the changes, and apply them to the database.

Here’s the migration flow:

  • First, create or modify entity models in C#.
  • Second, run a migration command to generate a migration file or script based on the model changes.
  • Third, apply the migration to the database to update the database schema.

Note that before running the migration commands, you need to install the Microsoft.EntityFrameworkCore.Tools package from NuGet Package.

Running EF Core migration commands

Once having the packaged install, you’re ready to explore the migration commands.

Help command

To view all available commands, you execute the following help command in the Package Manager Console (PMC):

get-help entityframeworkCode language: JavaScript (javascript)

It’ll show the following output (excerpt):

The Get-Help command shows all the commands available in Entity Framework Core. To get help on a specific command, you pass that command to the Get-Help command like this:

Get-Help command

For example, you can use the Get-Help command to display the help for the Add-Migration command:

get-help add-migrationCode language: JavaScript (javascript)

Output:

Adding the first migration

To create a migration, you use the Add-Migration command. The minimal requirement of the Add-Migration command is a migration name.

For example, the following creates a new migration called Initial:

Add-Migration InitialCode language: plaintext (plaintext)

The command will return the following output, indicating that the migration has been created successfully:

Build started...
Build succeeded.
To undo this action, use Remove-Migration.Code language: plaintext (plaintext)

If you view the HR project, you’ll see the Migrations directory created. The Migrations directory has two files:

20230608062832_Initial.cs – it starts with a timestamp and is followed by the migration name. The migration file defines a partial class that extends the Migration class. Typically, the class name is the same as the migration name, which is Initial in this example.

The Initial class has two methods Up() and Down().

  • The Up() method uses MigrationBuilder to create and manage database objects such as creating tables and adding/ removing columns based on the model.
  • The Down() method reverses the Up() method. If the Up() method creates a table, then the Down() method will drop it.

EF Core uses the Up() method to apply a migration and the Down() method to reverse it.

HRContextModelSnapshot.cs – EF Core will use the snapshot file during the subsequent migrations. More specifically, EF Core will use the snapshot file to compare the current state of the models with the previous snapshot and generate the migration scripts to update the database schema accordingly.

Note that the files in the Migrations directory can be a part of the source control like git. It means that you can manage their versions that are synchronized with the code base.

EF Core uses the following mapping conventions for naming tables and columns:

  • DBSet names are the table names.
  • Class property names are column names.

Applying a migration

To apply a migration to the database, you use the Update-Database command. It’ll do the following:

  • Reads migration file.
  • Generates SQL in memory.
  • Creates the database if it doesn’t exist.
  • Runs SQL on the database.

To generate SQL script file only, you use the Script-Migration command:

  • Reads migration file.
  • Generates SQL in memory.
  • Displays SQL in the editor.
  • Uses parameters to target file names etc.

It’s recommended to use the Update-Database command in the development database while using Script-Migration in the production database.

We’ll run the Script-Migration command first to preview the generated SQL script:

Script-Migration

It’ll display the following SQL code in the Visual Studio Editor:

IF OBJECT_ID(N'[__EFMigrationsHistory]') IS NULL
BEGIN
    CREATE TABLE [__EFMigrationsHistory] (
        [MigrationId] nvarchar(150) NOT NULL,
        [ProductVersion] nvarchar(32) NOT NULL,
        CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId])
    );
END;
GO

BEGIN TRANSACTION;
GO

CREATE TABLE [Departments] (
    [Id] int NOT NULL IDENTITY,
    [Name] nvarchar(max) NOT NULL,
    CONSTRAINT [PK_Departments] PRIMARY KEY ([Id])
);
GO

CREATE TABLE [Employees] (
    [Id] int NOT NULL IDENTITY,
    [FirstName] nvarchar(max) NOT NULL,
    [LastName] nvarchar(max) NOT NULL,
    [JoinedDate] datetime2 NOT NULL,
    [DepartmentId] int NULL,
    CONSTRAINT [PK_Employees] PRIMARY KEY ([Id]),
    CONSTRAINT [FK_Employees_Departments_DepartmentId] FOREIGN KEY ([DepartmentId]) REFERENCES [Departments] ([Id])
);
GO

CREATE INDEX [IX_Employees_DepartmentId] ON [Employees] ([DepartmentId]);
GO

INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion])
VALUES (N'20230608062832_Initial', N'7.0.5');
GO

COMMIT;
GO

Code language: SQL (Structured Query Language) (sql)

Note that before applying the migration to the database, we need to delete the existing HR database created in the previous tutorial.

Now, you can apply the migrations to create a new database and table by executing the following command in the PMC:

Update-DatabaseCode language: plaintext (plaintext)

EF Core will create the HR database and the following tables:

  • __EFMigrationsHistory – stores migration that has been applied to the database so that the database schema stays in sync with the models.
  • Departments – maps to the Department model class.
  • Employees – maps to the Employee model class.

The following shows the contents of the __EFMigrationHistory table:

Creating a new migration

Suppose you need a property called DateOfBirth to the Employee class and synchronize it to the database. To do that, you follow these steps:

First, define the DateOfBirth property in the Employee class:

namespace HR;


public class Employee
{
    public int Id { get; set; }
    public required string FirstName {  get; set; }
    public required string LastName {  get; set; }
    public required DateTime DateOfBirth  { get;set; }
    public required DateTime JoinedDate { get; set; }
    public Department? Department {  get; set; }
}
Code language: C# (cs)

Second, create a new migration by using the Add-Migration command:

 Add-Migration EmployeeDOBCode language: plaintext (plaintext)

Output:

Build started...
Build succeeded.
To undo this action, use Remove-Migration.Code language: plaintext (plaintext)

The command creates a new migration file in the Migrations directory:

20230608063613_EmployeeDOB.csCode language: plaintext (plaintext)

Note that your timestamp will be different. Here’s the content of the file:

using System;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace HR.Migrations
{
    /// <inheritdoc />
    public partial class EmployeeDOB : Migration
    {
        /// <inheritdoc />
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.AddColumn<DateTime>(
                name: "DateOfBirth",
                table: "Employees",
                type: "datetime2",
                nullable: false,
                defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
        }

        /// <inheritdoc />
        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropColumn(
                name: "DateOfBirth",
                table: "Employees");
        }
    }
}
Code language: C# (cs)

The Up() method adds a new column to the Employees table while the Down() method drops the column from it.

Third, run the Update-Database command to apply the migration to the database:

Update-DatabaseCode language: plaintext (plaintext)

It’ll synchronize the changes to the database. If you view the Employees table, you’ll see the new DateOfBirth column:

Summary

  • Use EF Core migration flow to apply changes from models to the database.
  • Use the Add-Migration command to create a new migration.
  • Use the Update-Database command to apply a migration to the database.
  • Use the Script-Migration command to generate an SQL script file.
Was this tutorial helpful ?