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

问题描述 投票:0回答:2

我正在使用实体框架和 C# 构建一个应用程序,在我的一个表中,我注意到我将该列命名为主键与外键列同名,即

dbo.MembershipTypes
表的主键位于“MembershipTypeId”上属性,并且与其有关系的
dbo.Customers
表在“MembershipTypeId”属性上有一个外键,即
public MembershipType MembershipTypeId { get; set; })

这引起了问题,所以我将

MembershipTypeId
重命名为
Id
(最初是
Id
,但该列不是标识列,即使在使用
[DatabaseGenereated(DatabaseGeneratedOption.Identity)]
[Key] 后,EF 也拒绝将其设为标识列) 
属性)。

我正在使用代码优先迁移,因此当我尝试使用

恢复更改时
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);
    }
}

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

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

这是用于生成 Customers 表的代码:

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。

预先感谢您的帮助!

c# sql-server asp.net-mvc entity-framework ef-code-first
2个回答
2
投票

感谢Gert Arnold在评论中回答这一问题。

我收到此错误的原因是我的迁移的

Id
方法中的
Down
列不是标识列。

我的理解是,由于

Id
列(在关系数据库中通常具有主键)不能为空,因此在那里插入0,因为这是字节或整数类型的默认值。

在我的

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

这是行不通的,因为

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

希望这对将来的人有帮助!


0
投票

@Vicktor 那么你是怎么解决的?

© www.soinside.com 2019 - 2024. All rights reserved.