我有一个客户,他已经运行了我的程序几年了,他们开始遇到奇怪的错误。 我的应用程序抛出了异常:
Cannot insert duplicate key in object
由于我几年没有触及代码,这让我很困惑。 它有时只发生过。
经过大量的调试和拔出头发后,我发现了发生的事情。在将项目添加到数据库的代码中,我调用了session.SaveOrUpdate
。
我无法回想起我在预期session.Save
方法中选择此内容的具体原因,但让我们继续。 (我正在为客户的代码更改此内容。)
所以似乎正在发生的是SaveOrUpdate
正在重用现有对象的ID并完全覆盖现有项目。我的代码抛出错误,但新项目保存到数据库中,并且不再有原始记录的跟踪。在我的nhibernate映射文档中,我使用hilo
生成器来获取对象ID。
我猜这只是发生,因为现在DB中有足够的项目来重新启动ID,我不知道。我有一个审计表,里面有很多记录。万的。但我截断该表以使备份更小。 (这可能导致这个问题)。
我试图找出是否有人能够最终说明SaveOrUpdate
是否由于某种原因重新使用现有ID或为什么现在将调用更改为Save
。如果这是一个已知问题,我将很容易入睡,如果没有,我需要进一步调试,看看是否还有一些情况我的客户端会丢失数据。
我的代码正在运行Nhibernate 3.3.3.4000,这是我编写此应用程序时的最新代码。
更新1
Session.Save
也在重复使用ID。
插入新记录时,我不断收到重复的密钥错误。但不是每次都只有一些时间。因此它非常随机,这使得调试变得困难。
答案 0 :(得分:1)
NHibernate用户已经请求了一种通用方法,该方法通过生成新标识符来保存瞬态实例,或者更新与其当前标识符关联的持久状态。 SaveOrUpdate()方法现在实现了此功能。
http://nhibernate.info/doc/nh/en/index.html#manipulatingdata-updating-detached)
基于此,如果NH在测试对象的密钥是否为“瞬态”或“持久”之前分配了对象的密钥,那么SaveOrUpdate()
的行为就会出现假设。即密钥生成器分配恰好使用的密钥,然后保存或更新逻辑支持更新,因为它确定对象是“持久的”。如果这是实际发生的事情,我会感到惊讶,因为它似乎是一个非常基本的错误。
如果启用日志记录,您将能够确定是否确实存在这种情况。
答案 1 :(得分:1)
我花了很多时间试图找出这个问题,但最后我放弃了。
到目前为止,我的解决方案似乎是将nhibernate id生成器类从hilo
更改为native
。
这确实需要我导出并重新导入我的所有数据,以便我可以重建表格,因此对于发现此帖子的其他人来说可能不是一个很好的解决方案,除非他们手动更改表格上的标识。 / p>