0

ここでわずかな問題:

私は2つのエンティティクラスを持っているとしましょう

class Parent {
    Set<Child> children;
}
class Child {
    SomethingElse reference;
}

現在、マッピングは基本的に次のとおりです。

<class name="Parent" lazy="false">
    <set name="children" lazy="false" cascade="all-delete-orphan">
        <key column="parent_id"/>
        <one-to-many class="Child"/>
    </set>
</class>

(ここでは ID マッピングとフィールドを省略しました。通常の生成 ID を使用します)

親のリストから要素を削除してから親をコミットするときのように、基本的にクリーンなデータベースを維持する必要があり、それに応じて削除された子データベースのエントリを削除する必要があります。子インスタンスは、後で削除できるようにする必要がある他のエンティティを参照するため、子インスタンスがデータベースに残っていると、参照されたオブジェクトを削除できません。

これまでにわかったこと: 休止状態の PersistentCollection ラッパーを所定の位置に保持する場合、以下で試したことはどれも機能するはずです。問題は、データベース オブジェクトがフレームワークのいくつかのレイヤーを通過することです。これには、Bean プロパティの抽象化を使用してセッターを呼び出す UI フレームワークと、オブジェクトのクローンを作成して前後にシリアル化するネットワーク通信レイヤーが含まれます。これらのレイヤーはどちらもコレクション インスタンスを内部的に置き換えるため、これらの PersistentCollection ラッパーを削除します。そうしないようにこれらを書き換えることはオプションではありません。

そうは言っても、私が試した8つのことはうまくいきませんでした:

1) リレーションを cascade="all" として構成し、session.update(parent) を使用します。

2) 関係を cascade="all-delete-orphan" として構成し、session.update(parent) を使用します。

3) リレーションを cascade="all" として構成し、session.merge(parent) を使用します

これらはすべて、「UPDATE CHILD SET parent.id = null WHERE parent.id = ...」を実行する休止状態になります。これは、親インスタンスをリロードするときに親リストから子を削除することに成功しますが、子インスタンスはデータベースに残り、参照されている他のエンティティを削除できません。

4-6) 構成 1-3 を使用し、さらに親キー列を非 null として定義する

これにより、休止状態は何もしなくなります。別の投稿で、キー列を非 null にすると削除されることを読みました。null への更新はオプションではなくなったため可能ですが、機能しません。コレクションから子を削除し、変更をコミットしてデータベースからインスタンスをリロードすると、子が再び表示されます。

7+8) 親キーが null 可能かどうかは問題ではありませんが、リレーションを cascade=all-delete-orphans として構成し、session.merge(parent) を使用します

これにより、PersistentCollection ラッパーが削除されたため、hibernate は例外「cascade="all-delete-orphan" を持つコレクションは、所有エンティティ インスタンスによって参照されなくなりました」をスローします。

私の問題を解決するために必要なのは、休止状態でオプション 1 ~ 3 のクエリを UPDATE ではなく DELETE として実行することだけです。PersistentCollection ラッパーなしでこれらを削除する方法でマッピングを構成するオプションが見つからないことを願っていますが、現在、そのようなオプションはないように見えます。これを設定する方法があるかどうか誰かが知っていますか?

/編集:明確にするために、私がしたいことの例:

Parent parent = new Parent();
parent.setChildren(new HashSet<Child>(Arrays.asList(new Child()))));
session.insert(parent)
// this correctly results in (approximately):
// SQL> INSERT INTO PARENT ...
// SQL> INSERT INTO CHILD ...

parent.setChildren(new HashSet<Child>()); // using .clear() is not an option.
session.update(parent);
// this results in:
// SQL> UPDATE CHILD set parent_id = null WHERE parent_id = ${id.of.parent}
// but i need this to result in:
// SQL> DELETE FROM CHILD WHERE parent_id = ${id.of.parent}
4

2 に答える 2

1

さて、どうやら今それを修正しました。問題は、空のセットを割り当てていなかったが、nullを割り当てていたことでした。どうやら、session.merge(updated)の場合、休止状態は突然空のコレクションとnullコレクションを区別します。プロパティに割り当てられた空のコレクションインスタンスでcascade="all-delete-orphan"と.merge()を使用すると、空のコレクションインスタンスの代わりにnullを割り当てると、前述の例外がスローされます。これは、キー列のnull可能性の制約に関係なく同じです。

通常、null値は空のコレクションと同じように機能するため、これが意図的な動作と見なされるかどうかはわかりません。これについてもう少し詳しく調べてから、バグレポートを作成できるかどうかを確認します。

更新:https ://hibernate.atlassian.net/browse/HHH-7726で発行

于 2012-10-26T21:47:31.617 に答える
0

これはあなたの質問に完全には答えませんが、少し役立つことを願っています。
まず、この説明とこれをご覧になることをお勧めします

ここで、子オブジェクトは親を参照せず、これは一方向の関係であると自分で言いました。あなたがどのようなマッピングを思いついたのかわかりませんが、これは:

Parent parent = new Parent();
parent.setChildren(Collections.singleton(new Child())));
session.save(parent);
// this correctly results in:
// SQL> INSERT INTO PARENT ...
// SQL> INSERT INTO CHILD ...

次の場合にのみ機能します。

  • cascadeセット内のマッピングが有効になっている(たとえば、そうでない場合、Hibernateは新しいオブジェクトcascade="all"の保存されていない一時インスタンスについて文句を言う)Child
  • parent_id列はnull許容です(そうでない場合、Hibernateはこのフィールドを事前設定することを期待します。これは、関係の反対側がマップされている場合にのみ可能です)

さらに、HibernateはSQL UPDATE、コメントで言及したこれら2つの挿入に加えて、もう1つ生成します(実際に表示される内容は、私が提供したリンクで説明されています)。

あなたがこれから何かを得ることを願っています。

于 2012-10-26T10:44:23.150 に答える