当IDENTITY_INSERT设置为OFF时,在表中插入显式值到标识列和复合键会出错。

14
我们最近在数据库中添加了一个新的“级别” - 添加了一个键“Company_ID”,放置在整个数据库中现有的ID Identity字段之上/之前。
例如,如果一个表格原来只有ID字段,现在它会有Company_ID字段,然后是ID字段,最后是其他字段。这样做的目的是允许ID根据提供给功能的每个不同Company_ID值进行自动递增(Company_ID 1可以拥有ID 1、2、3等;Company_ID 2可以拥有ID 1、2、3等)。
自动递增字段仍然是ID。一个示例表格如下:
    [dbo].[Project](
      [Company_ID] [int] NOT NULL,
      [ID] [int] IDENTITY(1,1) NOT NULL,
      [DescShort] [varchar](100) NULL,
      [TypeLookUp_ID] [int] NULL,
      [StatusLookUp_ID] [int] NULL,
      [IsActive] [bit] NOT NULL,
    CONSTRAINT [PK_Project] PRIMARY KEY CLUSTERED 
    (
      [Company_ID] ASC,
      [ID] ASC
    )

在引入Company_ID之前,我们执行CREATE操作时只需填写DescShort、TypeLookUp_ID、StatusLookUp_ID和IsActive字段,并将ID保留为默认值(可能是0)。

记录成功保存后,数据库会自动填充ID,并用此ID执行SHOW操作,等等。

现在,我们希望将Company_ID设置为指定的值,保留ID,并像以前一样填充字段。

    _db.Project.Add(newProject);
    _db.SaveChanges();

是的,我们想要指定 Company_ID 的值。我们希望 ID 能够像以前一样自动填充。 我们收到以下错误信息:

当 IDENTITY_INSERT 被设置为 OFF 时,在表 "Project" 中的标识列上插入显式值无效。

(译注:即不能手动指定 ID 值)

这是因为指定了 Company_ID 还是 ID 字段引起的?您知道如何纠正此问题吗?


1
你所描述的问题是,IDENTITY 规范是不断增加的,如果没有为该字段打开 IDENTITY_INSERT,则无法向其插入值。你不会得到 Company_ID 1 具有 ID 1、2、3 和 Company_ID 2 具有 ID 1、2、3 等的结果。你将得到 Company_ID 1 具有 ID 1、2、3 和 Company_ID 2 具有 ID 4、5、6 的结果。这可能对你来说不是问题,但只是提醒你,ID 不关心 Company_ID 中包含什么,并且不会改变其行为。 - Steve Pettifer
有趣。我看到了“复合键”的文档,就是这样解释的。我刚刚测试过了,可以看出你说的是对的。似乎在确定ID值时,Company_ID并不重要。为了满足这个条件,我们可以手动完成... - and_E
1
我明白这里发生了什么 - 我在原问题中提供的所有关于C#和MS Visual Studio的引用都被编辑删除了。我认为这不仅仅与SQL有关 - 我理解错误信息,如果我们只涉及SQL,那么这将是直截了当的,但是从Visual Studio进行调用是问题的一部分... - and_E
1
@steve-pettifer:经过进一步调查和审议,“有权力的人”已决定最好让Company_ID 1具有ID 1、2、3,而Company_ID 2具有ID 4、5、6。感谢您提出这个问题-最初的调查人员已被解雇!;) 如果我们的客户公司合并(这在过去发生过),数据库中“重复”的ID值将不允许轻松合并数据。这样,我们只需更新数据的Company_ID值,就可以继续进行了。再次感谢。 - and_E
很高兴你解决了它!当你需要扩展数据标识符以包含一些新的实体级别时,这总是一个棘手的任务。 - Steve Pettifer
10个回答

15

问题在于ID字段。如果将一个字段设置为IDENTITY,则通常不能将其指定为一个值,因为IDENTITY属性标记了该字段允许数据库自动分配递增值到该列。

要解决此问题,请删除ID的自动IDENTITY属性(如果您想要自动递增它,则可以在处理代码中执行此操作 - 获取字段中最高值,加上一个并将该值分配给新行)或者转到数据库并在表上设置IDENTITY_INSERT,这将临时允许您为IDENTITY字段分配值。

SET IDENTITY_INSERT [yourTableName] ON

--go back and run your C# code>

SET IDENTITY_INSERT [yourTableName] OFF

1
抱歉,如果这是一个愚蠢的问题,但您的新代码是否错误地尝试将值分配给iD,而应该分配给Company_ID?如果您使用序数而不是命名字段,则很容易出错。 - Bob Tway
感谢您在这里提供帮助。我们正在使用Visual Studio 2012(我在问题中没有明确提到)。我通过调试检查了正在使用的值 - NO,ID为0,Company_ID具有我们想要的值。所有其他字段的值也是正确/适当的。看起来ID = 0是一个值,但我们从未实际设置过它。 - and_E
这并不是一个愚蠢的问题,看起来最有可能的解释是某些东西正在尝试插入该字段 :) - Steve Pettifer
啊,我想我在这里看到了问题:无论您的应用程序代码中ID具有什么值,如果您在插入中指定该列,则会遇到麻烦。将ID列从您的INSERT中省略掉,那么一切都应该没问题了。很有可能您在_db.SaveChanges中调用了存储过程或一些内联SQL,是吗? - Steve Pettifer
我会将此标记为答案。感谢所有参与的人。 - and_E
显示剩余5条评论

11

睡醒后,我在 Visual Studio 的 C# 代码中发现了这个:[DatabaseGenerated(DatabaseGeneratedOption.Identity)]。每个 ID 字段都定义了这个内容告诉 Visual Studio 这个字段是一个标识,并在发送值到数据库时“不要管它”。当 Company_ID 出现在首位并有一个值时,告诉 Visual Studio 在其他地方有一个标识字段,使得 _db.Project.Add(newProject);_db.SaveChanges(); 能够按照要求执行。

这部分的答案与 Visual Studio 相关。我理解了 IDENTIY_INSERT 的 SQL 要求,感谢 @matt-thrower、@steve-pettifer 和其他贡献者。


或者使用流畅的配置,在属性上使用 HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity) - Cocowalla

7

对我有效的是进行了简单的EDMX更新。由于我之前设置了Identity Off,然后将其更改为自动,但没有更新Edmx。更新后正常工作。


这对我有用。缺点是我花了2个小时来解决这个问题。 - Max

4
在这种情况下对我有效的方法是在类的主键属性上设置一个属性:
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int DepartmentId { get; set; }

我的数据库中已经启用了 IDENTITY_INSERT。


1
从 Id 中删除 Identity 或添加
SET IDENTITY_INSERT [dbo].[Project] ON

通常情况下,ID会在没有用户干涉的情况下被插入,因此您会收到错误提示,因为您正在尝试输入数据。将其设置为开启将允许您输入所需的数据,或者简单地删除您正在向ID输入数据的代码,除非这是您需要的内容。

0

你的ID必须是唯一的。可以使用一些哈希算法来实现。(例如GUID)

[Key]
public string Id { get; set; }

public your_constructor()
{
    Id = Guid.NewGuid().ToString();
}

0

你可以尝试两件事并分别尝试吗?

  • 删除ID和Company_ID的主键字段
  • 将ID列排在第一位

0

好的,你已经有一个解决方案了... 但是考虑将ID作为唯一主键,将Company_Id作为外键


0

您的 SQL 表中外键的自增已经设置为自动 ... 因此,当您想要插入任何内容时,您需要从代码中删除此外键,如以下示例所示。

SQL 代码:

CREATE TABLE [dbo].[annexe1](
[cle] [int] IDENTITY(1,1) NOT NULL,
[tarif] [nvarchar](50) NULL,
[libele] [nvarchar](max) NULL)

Asp.Net 代码:

InsertCommand = "INSERT INTO [annexe6] ([cle], [tarif], [libele]) VALUES (@cle, @tarif, @libele)"

更正:

InsertCommand = "INSERT INTO [annexe6] ([tarif], [libele]) VALUES (@tarif, @libele)"

-2

如果您的表中有一个自增字段,请查看一下。将自增设置为NO,然后执行您的SQL语句。之后再将该字段重新设置为自增并再次同步。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接