流利的 NHibernate:"Cannot insert duplicate key in object" 即使 Id 是 GeneratedBy.Native() 或 Identity()
Fluent NHibernate: "Cannot insert duplicate key in object" even though Id is GeneratedBy.Native() or Identity()
我有一个相当简单的 table,带有适当的 Fluent NHibernate 映射,如下所示:
public class Blurb {
public virtual byte SimpleId { get; set; }
public virtual string Foo { get; set; }
public virtual string Bar { get; set; }
}
public class BlurbMap: ClassMap<Blurb> {
public BlurbMap() {
Id(x => x.SimpleId).Column("PK_SimpleID").GeneratedBy.Identity();
Map(x => x.Foo);
Map(x => x.Bar);
Table("dbo.SimpleTable");
}
}
请不要批评我用byte
作为ID,数据库是第三方预制的,我无法更改。
我现在想插入一些东西,所以我这样做:
var blurb = new Blurb {
Foo = "foo",
Bar = "bar"
};
using(var txn = session.BeginTransaction()) {
session.SaveOrUpdate(blurb); // <- boom!
txn.Commit();
}
在我写"boom"的地方,我得到了异常:
could not insert: [Foo.Bar.Blurb][SQL: INSERT INTO dbo.SimpleTable (Foo, Bar) VALUES (?, ?); select SCOPE_IDENTITY()] ---> System.Data.SqlClient.SqlException: Violation of PRIMARY KEY constraint 'PK_SimpleID'. Cannot insert duplicate key in object 'dbo.SimpleTable'. The duplicate key value is (1).
我再次尝试使用 SSMS 插入,我得到了同样的错误,但是随着查询的后续执行,错误消息变成了这样:
The duplicate key value is (1)
The duplicate key value is (2)
The duplicate key value is (3)
...
直到插入成功时按下未使用的键。
我已经尝试 GeneratedBy.Native()
但没有用。目前,我只能想到像
这样的解决方法
var lastBlurb = session.Query<Blurb>().Select(x => x.SimpleId).Max();
newBlurb.SimpleId = lastBlurb + 1;
session.SaveOrUpdate(newBlurb);
这是可行的,因为 "real" table 只包含 10 到 20 个元素,而且只有一个程序对 table 进行写访问(是的,我们真的知道并且可以确定这一点!)但是可能有另一种解决方法吗?还是(外部)数据库设计者做错了什么?
我post这是一个答案,因为它很长。
原来问题完全不同。我 运行 在我的测试数据库中加入了这个。我 运行 我的开发系统上的数据库副本用于集成测试。每次测试后运行,数据库都会被清除并重置为我从第三方收到它时的状态。
在那个重置过程中,我有这个小家伙:
EXEC sp_MSForEachTable "DBCC CHECKIDENT ( '?', RESEED, 0)"
这会将每个标识列的种子设置为 0,因此尝试插入新记录会导致错误。哦!
我现在将其更改为对每个 table 使用正确的值,单独发出 DBCC CHECKIDENT
命令,问题就消失了。
头部 -> 办公桌 -> 砰...
我有一个相当简单的 table,带有适当的 Fluent NHibernate 映射,如下所示:
public class Blurb {
public virtual byte SimpleId { get; set; }
public virtual string Foo { get; set; }
public virtual string Bar { get; set; }
}
public class BlurbMap: ClassMap<Blurb> {
public BlurbMap() {
Id(x => x.SimpleId).Column("PK_SimpleID").GeneratedBy.Identity();
Map(x => x.Foo);
Map(x => x.Bar);
Table("dbo.SimpleTable");
}
}
请不要批评我用byte
作为ID,数据库是第三方预制的,我无法更改。
我现在想插入一些东西,所以我这样做:
var blurb = new Blurb {
Foo = "foo",
Bar = "bar"
};
using(var txn = session.BeginTransaction()) {
session.SaveOrUpdate(blurb); // <- boom!
txn.Commit();
}
在我写"boom"的地方,我得到了异常:
could not insert: [Foo.Bar.Blurb][SQL: INSERT INTO dbo.SimpleTable (Foo, Bar) VALUES (?, ?); select SCOPE_IDENTITY()] ---> System.Data.SqlClient.SqlException: Violation of PRIMARY KEY constraint 'PK_SimpleID'. Cannot insert duplicate key in object 'dbo.SimpleTable'. The duplicate key value is (1).
我再次尝试使用 SSMS 插入,我得到了同样的错误,但是随着查询的后续执行,错误消息变成了这样:
The duplicate key value is (1)
The duplicate key value is (2)
The duplicate key value is (3)
...
直到插入成功时按下未使用的键。
我已经尝试 GeneratedBy.Native()
但没有用。目前,我只能想到像
var lastBlurb = session.Query<Blurb>().Select(x => x.SimpleId).Max();
newBlurb.SimpleId = lastBlurb + 1;
session.SaveOrUpdate(newBlurb);
这是可行的,因为 "real" table 只包含 10 到 20 个元素,而且只有一个程序对 table 进行写访问(是的,我们真的知道并且可以确定这一点!)但是可能有另一种解决方法吗?还是(外部)数据库设计者做错了什么?
我post这是一个答案,因为它很长。
原来问题完全不同。我 运行 在我的测试数据库中加入了这个。我 运行 我的开发系统上的数据库副本用于集成测试。每次测试后运行,数据库都会被清除并重置为我从第三方收到它时的状态。
在那个重置过程中,我有这个小家伙:
EXEC sp_MSForEachTable "DBCC CHECKIDENT ( '?', RESEED, 0)"
这会将每个标识列的种子设置为 0,因此尝试插入新记录会导致错误。哦!
我现在将其更改为对每个 table 使用正确的值,单独发出 DBCC CHECKIDENT
命令,问题就消失了。
头部 -> 办公桌 -> 砰...