C# 避免锁定';已在会话中(UniqueObjectException)
当需要再次初始化对象时,我在对象上调用此函数:C# 避免锁定';已在会话中(UniqueObjectException),c#,nhibernate,C#,Nhibernate,当需要再次初始化对象时,我在对象上调用此函数: public virtual void Initialize() { if (!HibernateSessionManager.Instance.GetSession().Contains(this)) { try { HibernateSessionManager.Instance.GetSession() .Lock(th
public virtual void Initialize()
{
if (!HibernateSessionManager.Instance.GetSession().Contains(this)) {
try
{
HibernateSessionManager.Instance.GetSession()
.Lock(this, NHibernate.LockMode.None);
}
catch (NonUniqueObjectException e) { }
}
}
我原以为通过检查包含(this)
可以防止两次初始化某个对象,但有时锁(this,NHibernate.LockMode.None)
会抛出非请求对象异常。到目前为止,我忽略了它,因为它是有效的,但我想知道原因和更好的方法来锁定我的对象
最好的问候,Expecto这很可能意味着你在某个地方违反了身份地图。这意味着您有两个具有相同数据库ID但引用标识不同的对象实例
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
});
}
使用(ISession session=SessionFactory.Factory.OpenSession())
{
int-someId=329;
Person p=session.Get(someId);
Person test=new Person(){BusinessEntityID=someId};
Assert.IsTrue(p.Equals(test));//您的代码可能认为对象是相等的,所以您可能希望下一行返回true
Assert.IsFalse(session.Contains(test));//但它们不是同一个对象
Assert.Throws(()=>
{
session.Lock(test,LockMode.None);//因此,当您要求nhibernate跟踪两个对象上的更改时,它会变得非常混乱
});
}
NHibernate(我猜任何ORM)都是通过跟踪对象的变化来工作的。所以在获得329人时,你要求NHibernate注意在一个人的特定实例上发生的任何事情。假设我们把他的名字改成詹姆
接下来,我们将获得另一个具有相同Id的person实例(在本例中,我们只是对其进行了更新,但有许多阴险的方法可以获得这样的对象)。想象一下,NHibernate会让我们将此附加到会话中。我们甚至可以将第二个对象的名字设置为类似Robb的东西
当我们刷新会话时,NHibernate无法知道数据库行是否需要同步到Robb或Jaime。因此,在这一切发生之前,它会将非唯一性抛向你的方向
理想情况下,这些情况不应该突然出现,但如果您非常确定发生了什么,您可能希望签出session.Merge,它允许您将跟踪状态强制为最后一次合并的对象(本例中为Robb).问题完全不同-如果我不重写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;
}
可能有多个线程试图同时执行此操作?我不明确使用线程。C是否可以自己以某种方式产生这种效果?merge()
可以,因为在显式调用save()
之前,我不会多次更改对象。但我不知道该把它放在哪里。在锁定之前
?只是合并
,而不是锁定
?目前我没有得到我所希望的结果。如果没有锁,我会得到lazyiinitializationexception
,如果使用merge和lock,我仍然会得到ununiqueobjectexceptions
。我读过关于使用update
或merge
,这取决于具体情况,但据我所知,我无法检查对象是否已经在会话中,至少不能使用contains()