尝试保存属于多对多关联的对象时,我收到了 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);
}
}
对象是一个未保存的瞬态实例 - 在合并之前保存瞬态实例