如何使用HiLo解决EF Core迁移错误?

时间:2019-05-03 08:24:23

标签: c# entity-framework asp.net-core entity-framework-core

一些背景。我正在使用:

  • .Net Core 2.2.3
  • Postgres作为我的数据库
  • Npgsql.EntityFramworkCore.PostgreSQL 2.20
  • EntityFramwork作为ORM

并且我在上下文中使用了简单的HiLo序列声明。

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

以下哪个创建我的迁移文件:

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.CreateSequence(
        name: "EntityFrameworkHiLoSequence",
        incrementBy: 10);

    migrationBuilder.CreateTable(
        name: "AspNetRoles",
        columns: table => new
        {
            Id = table.Column<int>(nullable: false)
                .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SequenceHiLo),
            Name = table.Column<string>(maxLength: 256, nullable: true),
            NormalizedName = table.Column<string>(maxLength: 256, nullable: true),
            ConcurrencyStamp = table.Column<string>(nullable: true)
        },
        constraints: table =>
        {
            table.PrimaryKey("PK_AspNetRoles", x => x.Id);
        });
    // other tables code goes here... All key has
    // .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SequenceHiLo)
}

一切正常,但是HiLo分配了奇怪的ID(但仍然是唯一的)。多么奇怪?让我解释。例如:

我有桌子

  • 订单
  • OrderItems
  • 角色(与以前完全无关)。

我为数据库分配了一个简单的种子,如下所示分配ID:

订单:

  • 1个MyOrder1

OrderItem:

  • 2 MyOrderItem1
  • 3 MyOrderItem2
  • 4 MyOrderItem3

角色:

  • 5个MyRole1
  • 6个MyRole2

因此,它似乎已为所有表共享HiLo。我以为每张桌子都是HiLo。

当我使用全新的迁移并执行操作时,我也会收到错误消息

  • dotnet ef database drop && dotnet ef database update

我遇到了错误(从波兰语翻译成英语):

42P07: relation "EntityFrameworkHiLoSequence" already exist

@UPDATE

由于@jpgrassi,我找到了解决奇怪ID的方法。我为每种型号命名为HiLo。看起来像这样:

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

    modelBuilder.Entity<OrderItem>()
        .Property(b => b.Id)
        .ForNpgsqlUseSequenceHiLo("OrderItemsHiLo");

    modelBuilder.Entity<Order>()
        .Property(b => b.Id)
        .ForNpgsqlUseSequenceHiLo("OrdersHiLo");
    // More sequences goes below...
}

现在一切听起来合乎逻辑。但是...我有新错误:

42P07: relation "OrderItemsHiLo" already exist

我的Up部分:

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.CreateSequence(
        name: "OrderItemsHiLo",
        incrementBy: 10);
    // more code...
}

在迁移的Down部分中,我有:

migrationBuilder.DropSequence(name: "OrderItemsHiLo");

我的问题是: 为什么在进行干净迁移时会引发此错误,以及如何消除此错误?

1 个答案:

答案 0 :(得分:1)

即使OP编辑了帖子并在我的帮助下基本解决了该问题,我也会发布实际答案,以便遇到相同“问题”的其他人也可以从中受益。

关于生成的“奇怪” ID。您需要为每个实体创建一个序列,因此它们不会“共享” ID。有关提供商文档的更多信息:HiLo Autoincrement Generation

覆盖OnModelCreating类中的DbContext并添加以下内容:

 modelBuilder.Entity<OrderItem>()
        .Property(b => b.Id)
        .ForNpgsqlUseSequenceHiLo($"Sequence-{nameof(OrderItem)}");

// same for others you want a sequence

重新添加迁移,您应该具有以下内容:

 migrationBuilder.CreateSequence(
                name: "Sequence-OrderItem",
                incrementBy: 10);

// Order entity code ommited
Id = table.Column<int>(nullable: false)
                        .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SequenceHiLo)

现在关于您的“第二个”问题,关于在运行dotnet ef database drop之后无法重新创建数据库,我无法重现它。我创建了一个示例ASP.NET Core App,该示例将EF Core与PostegreSQL结合使用,并且能够正常删除/创建数据库。

我将应用程序推送到了我的GitHub帐户,因此您可以克隆它并自己尝试:efcore-postgres-hilo-sequence