CREATE UNIQUE INDEX 语句因发现重复键而终止 EF

Posted

技术标签:

【中文标题】CREATE UNIQUE INDEX 语句因发现重复键而终止 EF【英文标题】:The CREATE UNIQUE INDEX statement terminated because a duplicate key was found EF 【发布时间】:2021-08-05 06:14:26 【问题描述】:

我正在使用 Entity Framework 和 C# 构建一个应用程序,并且在我的一个表中,我注意到我将主键列命名为与外键列同名,即 dbo.MembershipTypes 表的主键打开“ MembershipTypeId”属性,并且与之有关系的dbo.Customers 表在“MembershipTypeId”属性上具有外键,即public MembershipType MembershipTypeId get; set; )

这引起了问题,所以我将MembershipTypeId 重命名为Id(最初是Id,但该列不是身份列,并且即使在使用[DatabaseGenereated(DatabaseGeneratedOption.Identity)][Key] 属性)。

我正在使用代码优先迁移,所以当我尝试使用恢复更改时

update-database -TargetMigration:(migration before mistake goes here)

在包管理器控制台中,我收到此错误:

CREATE UNIQUE INDEX 语句终止,因为发现对象名称“dbo.MembershipTypes”和索引名称“PK_dbo.MembershipTypes”的重复键。重复键值为 (0)。 无法创建约束或索引。查看以前的错误。

当我尝试恢复到数据库的早期版本时,它给了我错误的迁移:

public partial class RenameIdColumnAndMakeItIdentityInMembershipTypeTable : DbMigration

    public override void Up()
    
        DropForeignKey("dbo.Customers", "MembershipTypeId", "dbo.MembershipTypes");
        DropPrimaryKey("dbo.MembershipTypes");
        AddColumn("dbo.MembershipTypes", "MembershipTypeId", c => c.Byte(nullable: false, identity: true));
        AddPrimaryKey("dbo.MembershipTypes", "MembershipTypeId");
        AddForeignKey("dbo.Customers", "MembershipTypeId", "dbo.MembershipTypes", "MembershipTypeId", cascadeDelete: true);
        DropColumn("dbo.MembershipTypes", "Id");
    
    
    public override void Down()
    
        AddColumn("dbo.MembershipTypes", "Id", c => c.Byte(nullable: false));
        DropForeignKey("dbo.Customers", "MembershipTypeId", "dbo.MembershipTypes");
        DropPrimaryKey("dbo.MembershipTypes");
        DropColumn("dbo.MembershipTypes", "MembershipTypeId");
        AddPrimaryKey("dbo.MembershipTypes", "Id");
        AddForeignKey("dbo.Customers", "MembershipTypeId", "dbo.MembershipTypes", "Id", cascadeDelete: true);
    

这是用于创建表的 T-SQL 代码 EF。我先用它的属性制作了表格,然后在单独的迁移中用参考数据填充它。

CREATE TABLE [dbo].[MembershipTypes] 
(
    [SignUpFee]        SMALLINT      NOT NULL,
    [DurationInMonths] TINYINT       NOT NULL,
    [DiscountRate]     TINYINT       NOT NULL,
    [Name]             NVARCHAR(255) DEFAULT ('') NOT NULL,
    [MembershipTypeId] TINYINT IDENTITY (1, 1) NOT NULL,

    CONSTRAINT [PK_dbo.MembershipTypes] 
        PRIMARY KEY CLUSTERED ([MembershipTypeId] ASC)
);

这是用于生成客户表的代码:

CREATE TABLE [dbo].[Customers] 
(
    [Id]                       INT            IDENTITY (1, 1) NOT NULL,
    [Name]                     NVARCHAR (255) NOT NULL,
    [IsSubscribedToNewsletter] BIT            DEFAULT ((0)) NOT NULL,
    [MembershipTypeId]         TINYINT        DEFAULT ((0)) NOT NULL,
    [Birthdate]                DATETIME       NULL,

    CONSTRAINT [PK_dbo.Customers] 
        PRIMARY KEY CLUSTERED ([Id] ASC),
    CONSTRAINT [FK_dbo.Customers_dbo.MembershipTypes_MembershipTypeId] 
        FOREIGN KEY ([MembershipTypeId]) REFERENCES [dbo].[MembershipTypes] ([MembershipTypeId]) 
            ON DELETE CASCADE
);
GO

CREATE NONCLUSTERED INDEX [IX_MembershipTypeId]
ON [dbo].[Customers]([MembershipTypeId] ASC);

这一切都是在我尝试修复 API 以使用 [HttpPost] 创建新客户时发生的。

请帮助我了解我收到此错误的原因以及如何解决它。另外,请帮助我理解为什么重复键从 0 而不是 1 开始。

提前感谢您的帮助!

【问题讨论】:

Down 方法中Id 不是标识列。 谢谢你,@GertArnold!这就是问题所在。在 Down 方法中使 Id 列成为标识列之后,一切都按预期工作。简单的错误,但我学到了很多试图弄清楚。 【参考方案1】:

感谢 Gert Arnold 在 cmets 中回答这个问题。

我收到此错误的原因是我迁移的Down 方法中的Id 列不是标识列。

我的理解是,由于Id列,在关系型数据库中经常有主键,不能为空,所以插入0,因为这是字节或整数类型的默认值。

在我的Up 方法中,我将Id 设为标识列,但由于已经存在默认值0,这会产生冲突,因为数据库现在正在为Id 生成一个以0 开头的值。

这不起作用,因为 Id 列是唯一的并且不能有重复的值。例如,即使您的数据库中有 5 个客户并删除了客户 4,其他客户的 ID 也不会为 4。

希望这对未来的人有所帮助!

【讨论】:

以上是关于CREATE UNIQUE INDEX 语句因发现重复键而终止 EF的主要内容,如果未能解决你的问题,请参考以下文章

CREATE UNIQUE INDEX 终止,因为发现了索引 ID 1 的重复键。最重要的主键为 'type 6c, len 9'。如何处理?

SQL基础语法—create index语句

CREATE UNIQUE INDEX 终止,因为发现对象名称 'dbo.table1' 和索引名称 'PK_table1' 有重复的键

Postgres的CREATE UNIQUE INDEX似乎停留了一段时间

Oracle基础语句

FOREIGN KEY 外键约束; UNIQUE和PRIMARY KEY 主键约束CREATE INDEX建立索引的使用