多対多の関連付けの一部であるオブジェクトを保存しようとすると、TransientObjectExceptionが発生します。なぜこれが起こっているのかはある程度理解していますが、私がやろうとしていることを適切に達成する方法を理解したいと思います。
一言で言えば、私がやろうとしていること:
私のアプリケーションには、ユーザーのリストとロールのリストがあります。ユーザーは複数の役割に割り当てることができ、役割は複数のユーザーに割り当てることができます。管理者がこれらの割り当てを実行できるWebページがあり、割り当ては双方向で実行できます(たとえば、管理者はユーザーを選択してから役割を追加できます。または、役割を選択してユーザーを追加できます)。
たとえば、管理者がユーザー「アリス」の「編集」をクリックしたとします。管理者には、使用可能な役割のリストと、すでにアリスに割り当てられている役割のリストが表示されます。次に、管理者は新しい役割をアリスに割り当て、[保存]をクリックします。
サーバーでは、一時的なUserオブジェクトと割り当てられたRoleオブジェクトがクライアントから受信されます。一時的なロールリストをUserオブジェクト(たとえばuser.Roles = roles
)に割り当てるだけで、問題なく更新できます。ただし、この割り当てを行う前にデータベースからUserを読み取った場合、関連付けられたRoleオブジェクトで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);
}
}
オブジェクトは保存されていない一時インスタンスです-マージする前に一時インスタンスを保存してください