9

こんにちは、みんな、

私は現在、コーディングとエンティティ モデルの何が問題なのかを理解しようとしています。一般的な DAO パターンと、カスケード ALL および orphanRemoval= true の注釈付きエンティティのみを使用した CRUD 操作に、hibernate 4.2 を使用しています。DayPlanElement弱いエンティティとのOneToMany 関係を持つ DayPlan エンティティがあります。DayPlanElement は java.util.Set に保存されますDayPlanElementにはプロパティ「order」があります。

DayPlanには、エンティティPersonとのOneToMany 関係もあります。java.util に保存されたエンティティPerson 。リスト

DayPlanElementは、DayPlanElementEntryウィーク エンティティと OneToMany の関係にあります。保存に使用される java.util.Set。Personエンティティも、 DayPlanElementEntryウィーク エンティティとのOneToMany 関係です。保存に使用される java.util.Set。DayPlan 、DayPlanElement および Personエンティティには、アプリケーションによって管理される ID が文字列として含まれています。DayPlanElementEntryウィーク エンティティには、EmbeddedId で注釈が付けられたDayPlanElementEntryId という複合 ID があり、parentPersonId と dayPlanElementId が含まれています。これ

つまり想像してみると、テーブルが存在し、その日の予定を表しています。列は 0 から 24 までの時間です。行は、1 日の計画から作業を進める必要がある人です。各列は DayPlanElement エンティティになります。各行は Person エンティティになります。そして、各セルは DayPlanElementEntry エンティティになります。

テーブルに新しい要素(Personsも)を追加して削除するだけで(リストから削除してから、DayPlanDAO.merge(dayPlan)を呼び出します-カスケードとorphanRemovalを希望します)-問題はありません。

指定された人物を並べ替えようとした場合 (java.util.List 内の操作を削除するだけ)、DayPlanDAO.merge(dayPlan) を呼び出した場合にのみ、次の例外がスローされます。

Caused by: java.lang.IllegalStateException: 
Error occurred while storing entity 
[DayPlanElementEntry [getDayPlanMode()=NONE, getCompositeId()=DayPlanElementEntryId [parentPersonId=874c8eac-8796-478d-a4d5-dd011f7d6a4b, dayPlanElementId=ab683a25-633e-419e-89b6-4aef7829d4f6], hashCode=-2039940039]]. 

An entity copy 
[org.hw.domain.DayPlanElementEntry#DayPlanElementEntryId [parentPersonId=874c8eac-8796-478d-a4d5-dd011f7d6a4b, dayPlanElementId=ab683a25-633e-419e-89b6-4aef7829d4f6]] 

was already assigned to a different entity 

[org.hw.domain.DayPlanElementEntry#DayPlanElementEntryId [parentPersonId=874c8eac-8796-478d-a4d5-dd011f7d6a4b, dayPlanElementId=ab683a25-633e-419e-89b6-4aef7829d4f6]].

       at org.hibernate.event.internal.EventCache.put(EventCache.java:192)

       at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:285)

       at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:151)

EventCache をデバッグし、問題の解決策を探し、実装された equals() および hashCode() メソッドをチェックするだけです - 成功しませんでした:-(( 注意、equals() メソッドには ID を使用します。たとえば、DayPlanElementEntry の複合 ID。その ID hashCode() で使用されます。エラー メッセージがわかりません。同じプロパティが 3 回出力されます。

イベント キャッシュのテスト クラスは見つかりましたが、次のユース ケース テストがわかりません。

    @Test
public void testCopyAssociatedWith2ExistingEntities() {
session.getTransaction().begin();
Simple entity1 = new Simple( 1 );
session.persist( entity1 );
Simple copy1 = new Simple( 1 );
cache.put(entity1, copy1);
Simple entity2 = new Simple( 2 );
session.persist( entity2 );
Simple copy2 = new Simple( 2 );
cache.put( entity2, copy2 );
session.flush();

try {
cache.put( entity1, copy2 );
fail( "should have thrown IllegalStateException");
}
catch( IllegalStateException ex ) {
// expected
assertTrue( ex.getMessage().startsWith( "Error occurred while storing entity [org.hibernate.event.internal.EventCacheTest$Simple#1]." ) );
}
session.getTransaction().rollback();
}

....

    @Entity
private static class Simple {
@Id
private int value;

public Simple(int value) {
this.value = value;
}

public int getValue() {
return value;
}

public void setValue(int value) {
this.value = value;
}
}

Id=1の Simple エンティティ entity1 があり、それを永続化します。次に、Simple エンティティ copy1 を作成し、それを値としてイベント キャッシュに入れます。キーとして永続エンティティ* 1 * が使用されます。次に、 Id=2でSimple entity* 2 *を作成し、それを永続化してから、id 2 で copy* 2 * エンティティを作成し、値としてイベント キャッシュに入れます。キーとして、永続化されたentity2が使用されました。なぜそのような状況が間違っていて、なぜ IllegalStateException をスローする必要があると予想されるのですか??

ご協力いただきありがとうございます!

4

6 に答える 6

10

Hibernate バージョン 4.3.4 以降では、修正があります。このアーティファクトを追加するだけです:

<dependency>
    <groupId>com.intersult</groupId>
    <artifactId>jpa-fix</artifactId>
    <version>1.1</version>
</dependency>

この修正により、MergeEventListener が、この種のマージを処理するものに置き換えられます。

于 2014-03-26T13:16:27.773 に答える
1

jpa構成ファイルで、以下に追加すると問題が解決します。

多対多の関係では、既存のエンティティとの合併操作を実行しているときに同じエンティティが繰り返される場合、Hibernate は違いを理解できるようになるまでそれらを区別できません。

properties.put("hibernate.event.merge.entity_copy_observer", "allow");
于 2017-09-09T18:46:40.490 に答える
1

これがテストのコンテキスト内にある場合は、session.flush() の後に session.clear() を使用することをお勧めします。これにより、問題の核心にあると思われるセッション キャッシュが効果的にクリアされます。

この問題の潜在的な理由 (考えられる):

  • 同じエンティティ コピーが、異なるエンティティ キーでキャッシュに追加されています。詳細を取得するには、EventCache.java にある put メソッドの下にブレークポイントを設定します。
  • 使用している休止状態のバージョンに新たに導入されたバグ。
于 2014-02-12T06:34:04.067 に答える
0

アイテムとコンポーネントの関係は一方向ですか、それとも双方向ですか? 双方向の場合は、Cascade.MERGE 呼び出しが Item に戻っていないことを確認してください。

関係から CascadeType.Merge を削除します

于 2016-06-07T09:47:49.650 に答える