Cannot insert explicit value for identity column in table ‘T_ADDRESS’ when IDENTITY_INSERT is set to OFF.
.Net 产生该错误的原因:
1、SQL Server层面(网上比较多的解释)
1.1 不能向 SQL Server 自增字段插入值
详细解释为:当我们的主键设置为自增,并且我们在insert数据时给主键赋值了,这个时候是不允许的。
如下面的 AddressKey 字段中的 IDENTITY(1,1)
CREATE TABLE [dbo].[T_ADDRESS](
[AddressKey] [int] IDENTITY(1,1) NOT NULL, --IDENTITY(1,1):起始值为1,自增值为1;
CONSTRAINT [PK_T_ADDRESS] PRIMARY KEY CLUSTERED
(
[AddressKey] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
1.2 如果你有特殊情况,需要插入特定的值,那么请参考如下
set identity_insert T_ADDRESS on
insert into T_ADDRESS (AddressKey) values(5)
set identity_insert T_ADDRESS off --注意的是,自增字段插入值后,要及时把 identity_insert 设置为 off
2、代码、框架层面导致( .Net );
无论你是Web Service(API)还是Web Client(客户端),基于二者的后台框架技术,总结如下:
无论DAL层是基于依赖注入还是基于DBContext上下文的,DB Model之间都不可以通过继承的方式进行定义
(例如:历史表和原表不可以通过继承的方式进行定义,否则在insert Into 历史表时,插入的会是原表,也因此会产生上面的错误信息;)
举例:Table_A有一个主键字段KeyId;Table_B类也有一个主键字段KeyId + DeleteBy字段;(基于DBContext的举例)
需求:删除Table_A表数据,并将数据备份到Table_B中;
public class Table_A
{
private int KeyId { get; set; } //主键 [int] IDENTITY(1,1) NOT NULL //原表有自增
}
//public class Table_B
//{
//private int KeyId { get; set; } //主键 [int] NOT NULL //历史表无自增
//private string DeleteBy { get; set; }
//}
public class Table_B : Table_A
{
private string DeleteBy { get; set; }
}
public static void main()
{
try
{
//public virtual DbSet<Table_A> Table_A { get; set; }
//public virtual DbSet<Table_B> Table_B { get; set; }
Table_A tableA = db.Table_A.Where(c => c.KeyId = 1).FirstOrDefault();//基于DBContext
Table_B tableB = new Table_B()
{
KeyId= tableA.KeyId,
DeleteBy = "Myself",
}
db.Table_A.Remove(tableA);
db.Table_B.Insert(tableB);
db.SaveChanges();// 在这里会报异常:
}
catch (Exception ex)
{
//Cannot insert explicit value for identity column in table 'Table_A' when IDENTITY_INSERT is set to OFF.
}
}
通过调试发现,代码运行到db.Table_B.Insert(tableB)时,SQLServer中实际是在向Table_A中插入tableB对象;
结论:此问题与依赖注入、EF、EF Core无关;在C#中用户自定义Class属于引用类型,实际数据存储在“堆”中;当历史表继承原表,那么在对历史表进行依赖注入或者在对历史表进行 DbSet<> 时,实际上是对原表进行的操作,而非历史表;
知识点:EF仍然是对ADO.Net的封装;
因此:在DAL层,无论是否是ADO.Net还是ASP.Net,一个Entity必须遵循一 一对应DB中的Table;如果有继承关系,那么父类必须是 abstract 的;
-------------------------欢迎讨论和指教-------------------------