【问题标题】:why seeded roles are deleted on every migration in asp .net core 2.1?为什么在 asp .net core 2.1 的每次迁移中都会删除种子角色?
【发布时间】:2019-03-02 05:20:30
【问题描述】:

每次迁移时,我都会遇到种子角色的奇怪行为。无论您做了什么更改,迁移都会删除种子角色并重新插入它们。下面给出的迁移是在项目中未进行任何修改时创建的。

所有其他模型均已正确播种,并且仅在对其进行修改时才会考虑迁移。

我正在使用带有个人身份验证的 ASP .NET Core 2.1

用于播种的 DbContext 类

 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
    }
}

迁移

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" }
            });
    }

如果我做错了,请告诉我播种角色的正确行为是什么。

【问题讨论】:

  • 你是如何在应用程序中播种这些数据的?
  • 上面给出了代码 => 使用 OnModelCreating
  • 代码中有context.Database.EnsureCreated()吗?我还有一个查询...添加此种子数据后,您是否在运行应用程序之前添加迁移并运行 update-database 命令?
  • 不,我没用过。
  • @camilo HasData() 是在 ef core 2.1 中引入的,所以请告诉我删除 ef-core-2.1 的标签会有什么帮助?

标签: c# entity-framework-migrations asp.net-core-2.1 asp.net-core-identity ef-core-2.1


【解决方案1】:

正如 Zubair Rana 提到的,如果您想在 Entity Framework .net Core 的 OnModelCreating 方法中使用这种播种数据的方法,那么您必须播种完整的对象字段!不仅仅是关键字段,这里是我为 IdentityRole 播种的代码示例:

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

如果你这样做:

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

然后在每次迁移时,ef 将继续删除旧对象并用相同的“名称”和“标准化名称”再次填充它,但“Id”和“ConcurrencyStamp”将再次生成新值。

【讨论】:

  • 即使您创建像 string adminId = Guid.NewGuid().ToString() 这样的 ID,它仍然会删除并创建记录。因此,最好对这些 ID 进行硬编码,这样 ID 对于每次迁移都不是新的。播种数据限制参考链接docs.microsoft.com/en-us/ef/core/modeling/data-seeding
【解决方案2】:

您可以按照以下步骤操作,而不是硬编码 Id 和 ConcurrencyStamp 来解决此问题:

  1. 创建一个初始迁移,该迁移将为角色播种

  2. 从您的 OnModelCreating 代码(即 HasData)中删除角色的播种逻辑

  3. 创建另一个迁移。这将具有删除 Up 角色并添加 Down 角色的逻辑,如下所示:

    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" },
        });
    

在迁移中删除此代码。迁移仍然存在,但不会执行任何操作。

基本上,您的初始迁移将创建数据(然后将其删除),然后继续进行的迁移不会与播种有关。

【讨论】:

    【解决方案3】:

    在阅读了许多问题和答案以及文档后,我才知道如果种子值没有主键,那么它们将在每次迁移时被删除并重新创建。

    通常我们不能在不提供主键值的情况下播种模型,但在 Microsoft 身份模型的情况下,它们可以在没有主键的情况下播种,因为主键是由身份方法本身创建的。因此,在每次迁移时,种子角色的主键都会更改,从而导致重新创建。

    【讨论】:

      猜你喜欢
      • 2019-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-10
      • 1970-01-01
      • 2019-04-10
      • 2012-01-19
      • 2020-08-06
      相关资源
      最近更新 更多