2

尝试保存属于多对多关联的对象时,我收到了 TransientObjectException。我有点理解为什么会发生这种情况,但想了解如何正确完成我正在尝试做的事情。

简而言之,我想做的是:

我的应用程序有一个用户列表和一个角色列表。用户可以分配多个角色,角色可以分配给多个用户。有一个网页,管理员可以在其中执行这些分配,并且可以双向完成分配(例如,管理员可以选择一个用户,然后向其添加角色;或者,选择一个角色并向其添加用户)。

例如,假设管理员在用户“Alice”上单击“编辑”。管理员会看到可用角色列表和已分配给 Alice 的角色列表。然后管理员为 Alice 分配一个新角色并单击“保存”。

在服务器上,从客户端接收临时用户和分配的角色对象。如果我只是将临时角色列表分配给用户对象(例如,user.Roles = roles),我可以很好地更新。但是,如果我在进行此分配之前碰巧从数据库中读取了用户,我会在关联的角色对象上得到一个 TransientObjectException。

类定义:

public class Role
{
    public Guid ID { get; set; }
    public virtual IList<User> Users { get; set; }
}

public class User
{
    public Guid ID { get; set; }
    public virtual IList<Role> Roles { get; set; }
}

映射:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="Role">
    <id name="ID">
      <generator class="guid"/>
    </id>

    <bag name="Users" table="Role_User" lazy="false" cascade="none">
      <key column="RoleID" />
      <many-to-many column="UserID" class="User" />
    </bag>
  </class>
</hibernate-mapping>

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="User">
    <id name="ID">
      <generator class="guid"/>
    </id>

    <bag name="Roles" table="Role_User" lazy="false" cascade="none">
      <key column="UserID" />
      <many-to-many column="RoleID" class="Role" />
    </bag>
  </class>
</hibernate-mapping>

要保存的代码(工作)

public void UpdateUser(User user, IList<Role> associatedRoles)
{
    using (var session = _sessionFactory.OpenSession())
    {
        user.Roles = associatedRoles;
        session.Merge<User>(user);
    }
}

要保存的代码(失败)

public void UpdateUser(User user, IList<Role> associatedRoles)
{
    using (var session = _sessionFactory.OpenSession())
    {
        User originalUser = session.Get<User>(user.ID);
        // Code that does some audit reporting/logging
        LogDifferences(originalUser, user);
        user.Roles = associatedRoles;
        session.Merge<User>(user);
    }
}

对象是一个未保存的瞬态实例 - 在合并之前保存瞬态实例

4

2 回答 2

1

Jouni Aro 是对的……您的会话中不能有两个具有相同 ID 的实体实例。

问题是以下之一:

  1. 您正在尝试originalUser从数据库加载,但user已附加到同一会话
  2. 你已经加载了originalUser,然后尝试合并user到同一个会话 - 首先驱逐 originalUser,正如 Jouni 建议的那样

无论如何,您真的需要加载原始用户来了解更改内容吗?NHibernate 还有其他方法可以做到这一点。你试过拦截器吗?

这是一种潜在的用法: http: //nhforge.org/wikis/howtonh/finding-dirty-properties-in-nhibernate.aspx谷歌更多。

于 2012-05-31T02:00:54.650 回答
0

Miroslav Popovic 的观点非常相关;但是,就我而言,由于数据库中的实体将版本设置为空 guid,因此我遇到了问题。这些记录是在 NHibernate 之外创建的。在保存它们之间的关联时,NHibernate 失败了,因为它检测到其中一个关联条目是由于其版本为 0 的瞬态对象,即使它引用了现有项目。

于 2012-06-04T19:17:35.793 回答