Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why seeded roles are deleted on every migration in asp .net core 2.1?

I am getting a strange behavior of seeded roles on every migration. No matter what changes you have made, migration will delete the seeded roles and will insert them again. Migration given below is created when no modification is done in the project.

All other models are seeded correctly and are considered in migration only if they are modified.

I am using ASP .NET Core 2.1 with Individual Authentication

DbContext Class for seeding

 public class ApplicationDbContext : IdentityDbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        #region Seed-Roles

        modelBuilder.Entity<IdentityRole>().HasData(new IdentityRole { Name = "SuperAdmin", NormalizedName = "SuperAdmin".ToUpper() });
        modelBuilder.Entity<IdentityRole>().HasData(new IdentityRole { Name = "Owner", NormalizedName = "Owner".ToUpper() });
        modelBuilder.Entity<IdentityRole>().HasData(new IdentityRole { Name = "Admin", NormalizedName = "Admin".ToUpper() });
        modelBuilder.Entity<IdentityRole>().HasData(new IdentityRole { Name = "Tester", NormalizedName = "Tester".ToUpper() });
        modelBuilder.Entity<IdentityRole>().HasData(new IdentityRole { Name = "User", NormalizedName = "User".ToUpper() });
        modelBuilder.Entity<IdentityRole>().HasData(new IdentityRole { Name = "Developer", NormalizedName = "Developer".ToUpper() });

        #endregion
    }
}

Migration

protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DeleteData(
            table: "AspNetRoles",
            keyColumns: new[] { "Id", "ConcurrencyStamp" },
            keyValues: new object[] { "4ae1956e-7895-4b0f-a390-22b5c41c1a62", "67b6f36e-5a3c-456b-89ef-c667cf9fe0d3" });

        migrationBuilder.DeleteData(
            table: "AspNetRoles",
            keyColumns: new[] { "Id", "ConcurrencyStamp" },
            keyValues: new object[] { "55ebaa87-e350-4d88-8d6f-2c7d833dd24d", "ed91ae85-918f-4651-b7f9-42f6dd90d9b2" });

        migrationBuilder.DeleteData(
            table: "AspNetRoles",
            keyColumns: new[] { "Id", "ConcurrencyStamp" },
            keyValues: new object[] { "6ae683e2-5df3-425f-8df7-66581ce56259", "6a4ff0dc-f82f-4c8d-85a1-0258bbf905d7" });

        migrationBuilder.DeleteData(
            table: "AspNetRoles",
            keyColumns: new[] { "Id", "ConcurrencyStamp" },
            keyValues: new object[] { "b06b021d-b369-44b3-a5d9-eeb3ef8e245d", "1363d06f-a0cb-4d10-8495-866c219f5560" });

        migrationBuilder.DeleteData(
            table: "AspNetRoles",
            keyColumns: new[] { "Id", "ConcurrencyStamp" },
            keyValues: new object[] { "b5331aad-70ec-47a2-8dd0-bc2508bdc353", "ae98d41a-e8fa-46dd-b081-96f9a1934e1e" });

        migrationBuilder.DeleteData(
            table: "AspNetRoles",
            keyColumns: new[] { "Id", "ConcurrencyStamp" },
            keyValues: new object[] { "b9fec2b5-6fd2-46a5-a960-a8d26f16d269", "413922ea-76f0-4d2d-8f1a-d9157fb31df0" });

        migrationBuilder.InsertData(
            table: "AspNetRoles",
            columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
            values: new object[,]
            {
                { "34e62595-2afc-43f9-bbcd-267773129d69", "c47b3378-ef47-4661-8a01-ceb2fbe34d7c", "SuperAdmin", "SUPERADMIN" },
                { "bc020d73-e415-4d4e-8dfe-577d81755f80", "77d4f05b-6677-4e99-9ada-3f6ec083c14b", "Owner", "OWNER" },
                { "cbfdbeb0-f800-4b42-b735-db1449fcc4e4", "2b8f6650-e2ee-46c1-a70f-36725fb893b3", "Admin", "ADMIN" },
                { "cd0e178d-f9cb-448e-8ecc-49914aa63c5d", "23ee6cfe-4bc2-4c6c-847a-d03aa0087e1f", "Tester", "TESTER" },
                { "4572a259-0d7c-4d1c-ad1d-e0230b7dd1fb", "bcc79860-9207-42bd-8a9c-8aeef0b5fe56", "User", "USER" },
                { "334fd762-7f37-48aa-afdc-a87ef8d0593e", "d929467e-44be-4a94-912f-071702316c85", "Developer", "DEVELOPER" }
            });
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DeleteData(
            table: "AspNetRoles",
            keyColumns: new[] { "Id", "ConcurrencyStamp" },
            keyValues: new object[] { "334fd762-7f37-48aa-afdc-a87ef8d0593e", "d929467e-44be-4a94-912f-071702316c85" });

        migrationBuilder.DeleteData(
            table: "AspNetRoles",
            keyColumns: new[] { "Id", "ConcurrencyStamp" },
            keyValues: new object[] { "34e62595-2afc-43f9-bbcd-267773129d69", "c47b3378-ef47-4661-8a01-ceb2fbe34d7c" });

        migrationBuilder.DeleteData(
            table: "AspNetRoles",
            keyColumns: new[] { "Id", "ConcurrencyStamp" },
            keyValues: new object[] { "4572a259-0d7c-4d1c-ad1d-e0230b7dd1fb", "bcc79860-9207-42bd-8a9c-8aeef0b5fe56" });

        migrationBuilder.DeleteData(
            table: "AspNetRoles",
            keyColumns: new[] { "Id", "ConcurrencyStamp" },
            keyValues: new object[] { "bc020d73-e415-4d4e-8dfe-577d81755f80", "77d4f05b-6677-4e99-9ada-3f6ec083c14b" });

        migrationBuilder.DeleteData(
            table: "AspNetRoles",
            keyColumns: new[] { "Id", "ConcurrencyStamp" },
            keyValues: new object[] { "cbfdbeb0-f800-4b42-b735-db1449fcc4e4", "2b8f6650-e2ee-46c1-a70f-36725fb893b3" });

        migrationBuilder.DeleteData(
            table: "AspNetRoles",
            keyColumns: new[] { "Id", "ConcurrencyStamp" },
            keyValues: new object[] { "cd0e178d-f9cb-448e-8ecc-49914aa63c5d", "23ee6cfe-4bc2-4c6c-847a-d03aa0087e1f" });

        migrationBuilder.InsertData(
            table: "AspNetRoles",
            columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
            values: new object[,]
            {
                { "6ae683e2-5df3-425f-8df7-66581ce56259", "6a4ff0dc-f82f-4c8d-85a1-0258bbf905d7", "SuperAdmin", "SUPERADMIN" },
                { "55ebaa87-e350-4d88-8d6f-2c7d833dd24d", "ed91ae85-918f-4651-b7f9-42f6dd90d9b2", "Owner", "OWNER" },
                { "4ae1956e-7895-4b0f-a390-22b5c41c1a62", "67b6f36e-5a3c-456b-89ef-c667cf9fe0d3", "Admin", "ADMIN" },
                { "b5331aad-70ec-47a2-8dd0-bc2508bdc353", "ae98d41a-e8fa-46dd-b081-96f9a1934e1e", "Tester", "TESTER" },
                { "b9fec2b5-6fd2-46a5-a960-a8d26f16d269", "413922ea-76f0-4d2d-8f1a-d9157fb31df0", "User", "USER" },
                { "b06b021d-b369-44b3-a5d9-eeb3ef8e245d", "1363d06f-a0cb-4d10-8495-866c219f5560", "Developer", "DEVELOPER" }
            });
    }

If i'm doing it wrong please update me what is the correct behavior of seeding roles.

like image 465
Zubair Rana Avatar asked Sep 26 '18 12:09

Zubair Rana


People also ask

Why is seed data useful for testing ASP NET core applications?

Creating Seed Data for ASP.NET Applications. When creating a new application I almost always need to have some initial seed data created when I first run or begin developing an application. This data helps create a baseline for all developers on an application and makes it easier to bring on new coders to the team.

What is seeding in ASP NET core?

Data seeding is the process of populating a database with an initial set of data. There are several ways this can be accomplished in EF Core: Model seed data. Manual migration customization.

Which method can be used to seed initial data in database using Entity Framework Core?

Seed Data in Entity Framework Core So as soon as we execute our migration files to create and configure the database, we want to populate it with some initial data. This action is called Data Seeding. So, we are using the HasData method to inform EF Core about the data it has to seed.


2 Answers

As Zubair Rana mentioned, if you want to use this method of seeding data in OnModelCreating method for Entity Framework .net Core then you have to seed complete object fields! not just the key field, here is my code example for seeding IdentityRole:

modelBuilder.Entity<IdentityRole>().HasData(new IdentityRole { Id = "117d1b41-6753-4622-89e6-8126a3b7d3f0", ConcurrencyStamp = "da7a4f42-ff3c-42a8-935a-62af68f978b0", Name = "Admin", NormalizedName = "Admin".ToUpper() });

if you do it like below:

 modelBuilder.Entity<IdentityRole>().HasData(new IdentityRole { Name = "Admin", NormalizedName = "Admin".ToUpper() });

then at each migration the ef will keep delete old objects and fill it again with same "Name" & "NormalizedName" but the "Id" & "ConcurrencyStamp" will generated again with new values.

like image 144
Ahmed Khalid Kadhim Avatar answered Oct 31 '22 16:10

Ahmed Khalid Kadhim


Rather than hardcoding the Id and ConcurrencyStamp to work around this issue, you can follow the following steps:

  1. Create an initial migration which will seed the roles

  2. Remove the seeding logic for Roles from your OnModelCreating code (i.e. the HasData)

  3. Create another migration. This will have logic to delete the Roles on Up and add the Roles on Down that looks like this:

    migrationBuilder.DeleteData(
        table: "AspNetRoles",
        keyColumn: "Id",
        keyValue: "1");
    
    ...
    
    migrationBuilder.InsertData(
        table: "AspNetRoles",
        columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
        values: new object[,]
        {
            { "1", "...GUID...", "MyRole", "MYROLE" },
        });
    

Remove this code inside the migration. The migration will still exist, but will do nothing.

Basically your initial migration will create the data (and delete it on down) and then migrations moving forward don't muck around with the seeding.

like image 37
ThisGuy Avatar answered Oct 31 '22 16:10

ThisGuy