这很可能意味着您在某处违反了身份映射。这意味着您有两个对象的实例,它们具有相同的数据库 ID,但引用标识不同。
Session.Contains 将检查引用相等性,但如果会话中已经有任何具有相同类型和 id 的东西,Lock 会抛出异常,这是一个不太严格的比较。
考虑在 AdventureWorks 数据库上进行的以下测试,使用 Equals 和 GetHashCode 的(非常幼稚且不推荐)简单实现
using (ISession session = SessionFactory.Factory.OpenSession())
{
int someId = 329;
Person p = session.Get<Person>(someId);
Person test = new Person() { BusinessEntityID = someId };
Assert.IsTrue(p.Equals(test)); //your code might think the objects are equal, so you'd probably expect the next line to return true
Assert.IsFalse(session.Contains(test)); //But they're not the same object
Assert.Throws<NonUniqueObjectException>(() =>
{
session.Lock(test, LockMode.None); //So when you ask nhibernate to track changes on both objects, it gets very confused
});
}
NHibernate(我猜是任何 ORM)通过跟踪对象的变化来工作。因此,在 Get'ing Person 329 中,您要求 NHibernate 关注某个 Person 的特定实例发生的任何事情。假设我们将他的名字改为 Jaime。
接下来,我们得到另一个具有相同 ID 的 person 实例(在这种情况下,我们只是对其进行了新的处理,但是有很多隐蔽的方法可以获取这样的对象)。想象一下,NHibernate 也会让我们将它附加到会话中。我们甚至可以将第二个对象的名字设置为类似 Robb。
当我们刷新会话时,NHibernate 无法知道数据库行是否需要同步到 Robb 或 Jaime。所以它会在这种情况发生之前抛出非独特的方式。
理想情况下,这些情况不应该出现,但如果您非常确定发生了什么,您可能需要查看 session.Merge,它可以让您将跟踪状态强制为最后合并的任何内容(示例中为 Robb) .