2

多対多の関連付けの一部であるオブジェクトを保存しようとすると、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);
    }
}

オブジェクトは保存されていない一時インスタンスです-マージする前に一時インスタンスを保存してください

4

2 に答える 2

1

JouniAroは正しいです...セッションに同じIDを持つエンティティの2つのインスタンスを含めることはできません。

問題は次のいずれかです。

  1. originalUserDBからロードしようとしていますが、userはすでに同じセッションに接続されています
  2. をロードしoriginalUser、その後user、同じセッションにマージしようとしました-Jouniが提案したように、最初にoriginalUserを削除します

とにかく、変更が何であるかを知るためだけに、本当に元のユーザーをロードする必要がありますか?NHibernateでそれを行う他の方法があります。インターセプターを試しましたか?

考えられる使用法の1つは次のとおりです:http://nhforge.org/wikis/howtonh/finding-dirty-properties-in-nhibernate.aspxGoogleはもう少し。

于 2012-05-31T02:00:54.650 に答える
0

ミロスラフ・ポポビッチのポイントは非常に関連性があります。ただし、私の場合、バージョンが空のGUIDに設定されているデータベース内のエンティティが原因で問題が発生していました。これらのレコードはNHibernateの外部で作成されました。それらの間の関連付けを保存するときに、NHibernateは、既存のアイテムを参照していても、バージョンが0であるため、関連付けエントリの1つを一時オブジェクトとして検出したために失敗していました。

于 2012-06-04T19:17:35.793 に答える