当需要再次初始化时,我会在我的对象上调用此函数:
public virtual void Initialize()
{
if (!HibernateSessionManager.Instance.GetSession().Contains(this)) {
try
{
HibernateSessionManager.Instance.GetSession()
.Lock(this, NHibernate.LockMode.None);
}
catch (NonUniqueObjectException e) { }
}
}
我认为我可以通过检查Contains(this)
来阻止初始化两次,但有时会Lock(this, NHibernate.LockMode.None)
抛出NonUniqueObjectException
。到目前为止,我忽略它,因为它有效,但我想知道原因和锁定我的对象的更好方法。
最好的问候,Expecto
答案 0 :(得分:3)
这很可能意味着您在某处违反了身份地图。这意味着您有两个对象实例,它们具有相同的数据库ID,但具有不同的引用标识。
Session.Contains将检查引用相等性,但是如果存在任何类型相同的内容,Lock将抛出异常。 id已经在会话中,这是一个不那么严格的比较。
在AdventureWorks数据库上考虑以下测试,其中包含一个(非常天真且未经推荐的)Equals& amp;的简单实现。 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关注那个特定个人实例发生的事情。假设我们将他的名字改为Jaime。
接下来,我们得到另一个具有相同Id的人的实例(在这种情况下,我们只是新建了它,但有许多阴险的方法来获得这样的对象)。想象一下,NHibernate也会让我们将它附加到会话中。我们甚至可以将第二个对象的名字设置为Robb。
当我们刷新会话时,NHibernate无法知道数据库行是否需要同步到Robb或Jaime。因此,在可能发生之前,它会抛出非独特的方式。
理想情况下,这些情况不应该出现,但如果您非常确定发生了什么,您可能需要查看session.Merge,它可以让您将跟踪状态强制转换为最后合并的内容(Robb in例子)。
答案 1 :(得分:0)
问题完全不同 - 如果我不覆盖Equals()
,则包含通过引用检查相等性。现在它适用于我的问题代码!
public override bool Equals(object obj)
{
if (this == obj) {
return true;
}
if (GetType() != obj.GetType()) {
return false;
}
if (Id != ((BaseObject)obj).Id)
{
return false;
}
return true;
}