Entity Framework Code First Migration In Asp.net Core

Code First Entity Framework Migration In Asp.Net Core By Sagar Jaybhay

Migration helps to sync database schema with the model classes. In entity framework code first we have different database initialization strategies like .

CreateDatabaseIfNotExists, DropCreateDatabaseIfModelChanges, and DropCreateDatabaseAlways.and there is one problem with these strategies like if you have existing stored procedure,triggers or you have any other database objects. When you use the above-mentioned strategies they will re-create the database so you may lose your data and other db objects.

So entity framework core introduces a migration tool that automatically updates database schema and if in future your model changes it will reflect that to your underlying table.

There are two kinds of Migration:

  1. Automated Migration
  2. Code-based Migration

Till now in previous links we add connection string in appsettings.json file and add repository and context classes.

And when we run this application we got following error.

Can Not Open DataBase Entity Framework Error
Cannot open database "StudentDB" requested by the login. The login failed.
Login failed for user 'DESKTOP-ONEBTMN\Sagar'.

Now why we got this error because we don’t add entity core migration and right now we don’t have that StudentDb database on our local server and tables also not present there. So to overcome this error we need to add migration.

Commands used in Entity Framework Code First Migration

There are many commands which help you for migration but we start with

Get help you need to fire this command in the package manager console.

How to Open package manager see below image

How to Open Package Manager In Visual Studio 2019

A) Get-Help about_entityframeworkcore

Below is the output of this get-help commands

                     _/\__
               ---==/    \\
         ___  ___   |.    \|\
        | __|| __|  |  )   \\\
        | _| | _|   \_/ |  //|\\
        |___||_|       /   \\\/\\

TOPIC
    about_EntityFrameworkCore

SHORT DESCRIPTION
    Provides information about the Entity Framework Core Package Manager Console Tools.

LONG DESCRIPTION
    This topic describes the Entity Framework Core Package Manager Console Tools. See https://docs.efproject.net for
    information on Entity Framework Core.

    The following Entity Framework Core commands are available.

        Cmdlet                      Description
        --------------------------  ---------------------------------------------------
        Add-Migration               Adds a new migration.

        Drop-Database               Drops the database.

        Get-DbContext               Gets information about a DbContext type.

        Remove-Migration            Removes the last migration.

        Scaffold-DbContext          Scaffolds a DbContext and entity types for a database.

        Script-Migration            Generates a SQL script from migrations.

        Update-Database             Updates the database to a specified migration.

SEE ALSO
    Add-Migration
    Drop-Database
    Get-DbContext
    Remove-Migration
    Scaffold-DbContext
    Script-Migration
    Update-Database

A) Automatic Migration:

For this use below command

enable-migrations –EnableAutomaticMigration:$true

Once the command runs successfully, it creates an internal sealed Configuration class derived from DbMigrationConfiguration in the Migration folder in your project.

B) Code-Based Migration in Entity Framework 6

  1. Add-Migration– this command is used for add migration but for this, you need to pass name for the migration
PM> Add-Migration
cmdlet Add-Migration at command pipeline position 1
Supply values for the following parameters:
Name: firstmigration
Microsoft.EntityFrameworkCore.Infrastructure[10403]
      Entity Framework Core 2.2.6-servicing-10079 initialized 'OurDbContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer' with options: MaxPoolSize=128 
To undo this action, use Remove-Migration.
Add-Migration In Entity Framework Code First

As shown in command we give the name to add-migration command so it will create a class of that name first in our case firstmigration.

public partial class firstmigration : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Students",
                columns: table => new
                {
                    StudentId = table.Column<int>(nullable: false)
                        .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
                    FullName = table.Column<string>(nullable: false),
                    Address = table.Column<string>(nullable: false),
                    Division = table.Column<int>(nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Students", x => x.StudentId);
                });
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Students");
        }
    }

After this command, you need to use an update–database command which is given below

PM> update-database
Microsoft.EntityFrameworkCore.Infrastructure[10403]
      Entity Framework Core 2.2.6-servicing-10079 initialized 'OurDbContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer' with options: MaxPoolSize=128 
Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (22ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT OBJECT_ID(N'[__EFMigrationsHistory]');
Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (5ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      CREATE TABLE [__EFMigrationsHistory] (
          [MigrationId] nvarchar(150) NOT NULL,
          [ProductVersion] nvarchar(32) NOT NULL,
          CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId])
      );
Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT OBJECT_ID(N'[__EFMigrationsHistory]');
Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT [MigrationId], [ProductVersion]
      FROM [__EFMigrationsHistory]
      ORDER BY [MigrationId];
infoinfo:    Applying migration '20190902071133_firstmigration'.
: Microsoft.EntityFrameworkCore.Migrations[20402]
      Applying migration '20190902071133_firstmigration'.
Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      CREATE TABLE [Students] (
          [StudentId] int NOT NULL IDENTITY,
          [FullName] nvarchar(max) NOT NULL,
          [Address] nvarchar(max) NOT NULL,
          [Division] int NOT NULL,
          CONSTRAINT [PK_Students] PRIMARY KEY ([StudentId])
      );
Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion])
      VALUES (N'20190902071133_firstmigration', N'2.2.6-servicing-10079');
Done.

Update database command takes one parameter which migration name and if you don’t specify migration name it will automatically get latest migration name to do a task. If you have more than one migration then you can provide a name to this so only for this update will be applied.

This command first creates StudentDB which is our database name is created and after database created it will create student table under StudentDB.

EntityFrameworkCore Migration Commands
EntityFrameworkCore Migration Commands

How to seed Data in Asp.net core Entity Framework?

Seeding means what? initially when you add migration and all that you don’t have any data in a table so you need to add some demo data in the table and how you gone add that by using OnModelCreating method. You need to override this method in OurDbContext class.

public class OurDbContext:DbContext
    {
        public DbSet<Student> Students { get; set; }
        public OurDbContext(DbContextOptions<OurDbContext> options):base(options)
        {
                
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Student>().HasData(
                new Student
                {
                    StudentId = 1,
                    Division = Divi.A_10,
                    Address = "abcd efgh",
                    FullName = "abc"
                },
                new Student
                {
                    StudentId = 2,
                    Division = Divi.A_10,
                    Address = "werr",
                    FullName = "xyz"
                }
            );
        }
    }

This is the class and in this we override the OnModelCreating method. In that we add 2 demo entity in that.

After doing this you need to fire command Add-Migration with-Migration-name, below is the command.

Add-Migration InitialSeeding
Microsoft.EntityFrameworkCore.Infrastructure[10403]
      Entity Framework Core 2.2.6-servicing-10079 initialized 'OurDbContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer' with options: MaxPoolSize=128 
To undo this action, use Remove-Migration.

After successfully run this command you need to fire another command which is 
Update database
update-database 
Microsoft.EntityFrameworkCore.Infrastructure[10403]
      Entity Framework Core 2.2.6-servicing-10079 initialized 'OurDbContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer' with options: MaxPoolSize=128 
infoverbose: Executed DbCommand (11ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (11ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT OBJECT_ID(N'[__EFMigrationsHistory]');
Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT OBJECT_ID(N'[__EFMigrationsHistory]');
Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT [MigrationId], [ProductVersion]
      FROM [__EFMigrationsHistory]
      ORDER BY [MigrationId];
Microsoft.EntityFrameworkCore.Migrations[20402]
      Applying migration '20190902100615_InitialSeeding'.
Applying migration '20190902100615_InitialSeeding'.
Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (22ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      IF EXISTS (SELECT * FROM [sys].[identity_columns] WHERE [name] IN (N'StudentId', N'Address', N'Division', N'FullName') AND [object_id] = OBJECT_ID(N'[Students]'))
          SET IDENTITY_INSERT [Students] ON;
      INSERT INTO [Students] ([StudentId], [Address], [Division], [FullName])
      VALUES (1, N'abcd efgh', 4, N'abc');
      IF EXISTS (SELECT * FROM [sys].[identity_columns] WHERE [name] IN (N'StudentId', N'Address', N'Division', N'FullName') AND [object_id] = OBJECT_ID(N'[Students]'))
          SET IDENTITY_INSERT [Students] OFF;
Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (11ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      IF EXISTS (SELECT * FROM [sys].[identity_columns] WHERE [name] IN (N'StudentId', N'Address', N'Division', N'FullName') AND [object_id] = OBJECT_ID(N'[Students]'))
          SET IDENTITY_INSERT [Students] ON;
      INSERT INTO [Students] ([StudentId], [Address], [Division], [FullName])
      VALUES (2, N'werr', 4, N'xyz');
      IF EXISTS (SELECT * FROM [sys].[identity_columns] WHERE [name] IN (N'StudentId', N'Address', N'Division', N'FullName') AND [object_id] = OBJECT_ID(N'[Students]'))
          SET IDENTITY_INSERT [Students] OFF;
Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion])
      VALUES (N'20190902100615_InitialSeeding', N'2.2.6-servicing-10079');
Done.

After doing all this you see below InitialSeeding which is our migration name class is created.

public partial class InitialSeeding: Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.InsertData(
                table: "Students",
                columns: new[] { "StudentId", "Address", "Division", "FullName" },
                values: new object[] { 1, "abcd efgh", 4, "abc" });

            migrationBuilder.InsertData(
                table: "Students",
                columns: new[] { "StudentId", "Address", "Division", "FullName" },
                values: new object[] { 2, "werr", 4, "xyz" });
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DeleteData(
                table: "Students",
                keyColumn: "StudentId",
                keyValue: 1);

            migrationBuilder.DeleteData(
                table: "Students",
                keyColumn: "StudentId",
                keyValue: 2);
        }
    }
Initial Seed Data In Entity Core Code First Migration
Initial Seed Data In Entity Core Code First Migration

In our OurDbContext  class we override this method and we add some demo data, but here one thing is that if you want to add so many records your code becomes very cluttered so avoid this we use Extention method for this we need to create on class and in that create one static method which takes one parameter is ModelBuilder like below.

Model Builder Seed Data Entity Framework Code First Migration
Model Builder Seed Data Entity Framework Code First Migration

Below is our extension method class.

public static class ModelBuilderSeeding
    {
        public static void Seed(this ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Student>().HasData(
                new Student
                {
                    StudentId = 1,
                    Division = Divi.A_10,
                    Address = "abcd efgh",
                    FullName = "abc"
                },
                new Student
                {
                    StudentId = 2,
                    Division = Divi.A_10,
                    Address = "werr",
                    FullName = "xyz"
                }
            );
        }
    }

How keep Domain Models and Database schema in sync using migration in asp.net core MVC?

add-migration <name of migration>

When developing applications, the model is likely to change often as new requirements come to light. The database needs to be kept in sync with the model. The migrations feature enables you to make changes to your model and then propagate those changes to your database schema.

When you create a migration, the framework compares the current state of the model with the previous migration if one exists and generates a file containing a class inheriting from Microsoft.EntityFrameworkCore.Migrations.Migration featuring an Up and a Down method. The class is given the same name as you specified for the migration. The filename itself is the name of the migration prefixed with a timestamp.

The Up method contains C# code that applies any changes made to the model to the schema of the database since the last migration was generated. The Down method reverses those changes, restoring the database to the state of the previous migration. A ModelSnapshot file is also created or updated, depending on whether one previously existed.

  • Use migrations to keep domain models and database schema in sync
  • Add new migration we use Add-Migration command
  • To update the database with the latest migration use update-database command
  • Remove the latest migration which is not applied yet to database use remove-migration command
  • __migrationhistory table in our created database is used to keep track of applied migration.
  • ModelSnapShot.cs file contains a snapshot of the current model and is used to determine what has changed when adding the next migration

To remove migration that is already applied to the database we need to first use the Update-Database command to undo the database changes applied by the migration.

Next use remove-migration command to remove migration.

Sagar Jaybhay, from Maharashtra, India, is currently a Senior Software Developer. He has continuously grown in the roles that he has held in the more than seven years he has been with this company. Sagar Jaybhay is an excellent team member and prides himself on his work contributions to his team and company as a whole.

Related posts