1

当需要再次初始化对象时,我会在对象上调用此函数:

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. 到目前为止,我忽略了它,因为它有效,但我想知道锁定对象的原因和更好的方法。

最好的问候, 期待

4

2 回答 2

3

这很可能意味着您在某处违反了身份映射。这意味着您有两个对象的实例,它们具有相同的数据库 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) .

于 2012-08-13T20:15:51.557 回答
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;
    }
于 2012-08-21T06:49:30.477 回答