2013-11-22 15 views
9

「実体のコピーは既に別のエンティティに割り当てられていた」:GSON +休止状態:原因同一のオブジェクト私は、次のJSON持っ

{ 
    id: 123, 
    subObjects: [ 
     { 
      id: 564, 
      name: "foo", 
      contry: { 
       id: 1, 
       name: "Germany" 
      } 
     }, 
     { 
      id: 777, 
      name: "bar", 
      contry: { 
       id: 1, 
       name: "Germany" 
      } 
     } 
    ] 
} 

をそしてGsonを使用して、それをデシリアライズ。その後、私はJPAエンティティをマージする必要があります。

Model model = new Gson().fromJson(json, modelClass); 
model = entityManager.merge(model) 

リフレッシュがサブオブジェクトにし、国へのダウンモデルからカスケードされます。 これにより、Hibernateによって "エンティティコピーがすでに別のエンティティに割り当てられています"という例外が発生します。

私は異なる国を使用する場合に機能します。 両方のサブオブジェクトがそのコンテンションの同じインスタンスを参照するように、1つのオブジェクトから別のオブジェクトへcountryインスタンスをコピーすると機能します。

両方の国で同じ値が設定されています。両方とも同じhashCodeを持ちます。 両国は同じですが、異なるインスタンスであるため==ではありません。

this questionに記載されているtippsは私を助けませんでした。

私は、Hibernate 4.1.3私は、私はオブジェクトの種類を知っている必要はありませんし、そのオブジェクトは、論理的に同一であり、一般的な方法でこの問題を解決するにはどうすればよい

java.lang.IllegalStateException: An entity copy was already assigned to a different entity. 
    at org.hibernate.event.internal.EventCache.put(EventCache.java:184) 
    at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:285) 
    at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:151) 
    at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:914) 
    at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:896) 
    at org.hibernate.engine.spi.CascadingAction$6.cascade(CascadingAction.java:288) 
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:380) 
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323) 
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208) 
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165) 
    at org.hibernate.event.internal.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:439) 
    at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:308) 
    at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:151) 
    at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:914) 
    at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:896) 
    at org.hibernate.engine.spi.CascadingAction$6.cascade(CascadingAction.java:288) 
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:380) 
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323) 
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208) 
    at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:409) 
    at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:350) 
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:326) 
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208) 
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165) 
    at org.hibernate.event.internal.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:439) 
    at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:308) 
    at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:151) 
    at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:76) 
    at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:904) 
    at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:888) 
    at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:892) 
    at org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:874) 
    at play.db.jpa.GenericModel.merge(GenericModel.java:234) 
    [...] 

2.2決勝とGson

を使用していますか?

+0

@AndreiI使用しているフレームワーク(再生1.2.x)は、使用するパッチによって特定のバージョンが必要なため、アップグレードはオプションではありません。私は本当にそれを一般的な方法で解決する必要があります。なぜなら、私は異なるエンティティで同じケースを持っているからです。大きなオブジェクトをWebサーバーからmvc-javascriptフレームワーク(AngularJS)にトランスポートして、サーバ。オブジェクトは複雑な企業データを表現しています。 – maklemenz

+0

同じIDを持ち、名前の異なる2つの国が来たときに、どのような振る舞いになると思いましたか?この質問だけでは答えにくいので、インターフェースからすべてを受け入れるのではなく、IDをロードするDTOを使用するように提案します。また、おそらくあなたはあまりにも多くのユーザーインターフェイスを信頼しています。既存のIDを持つ国またはそのインタフェースで使用することが許可されていない国を追加することを考えるだけです。つまり、データをDBでマージするのではなく、データを検証する必要があります。 –

+0

このアプリケーションのユーザーは、通常とは異なる方法でデータを変更するために必要な知識がなくても、100%信頼できる管理ユーザーですが、検証が必要です。私のケースでは、彼らはcontriesを変更する必要はありませんが、彼らは正しいものを選択する必要があります。他のケースは、実装するためにはるかにコンパイルされているかもしれません。私のケースでは、おそらくそのオブジェクトのcontriesのIDを取得するenougthと休止は、残りの部分を行うことができますが、彼らは同じインスタンスの場合のみ。 – maklemenz

答えて

2

はマージを使用していない私の実用的なソリューションです:

私は結合時にフィールドを反復するためにリフレクションを使用しています。フィールドがエンティティまたはエンティティのコレクションであるかどうかを確認し、jsonにIDが提供されている場合はfindByIDを呼び出し、エンティティを取得しない場合はエンティティの新しいインスタンスを作成します。 その後、jsonに存在するフィールド値をリフレクションによって添付エンティティにコピーします。 私はエンティティ間の関係を処理するために再帰的に行います。 その後、サブオブジェクトを添付して結合したすべてのエンティティを完全にマージして添付したバージョンを取得しました。 私は何の問題も

重要な注意せずにそれを保存することができます:

アンドレイは、私が発生し、完全な国を取得しないために、APIを変更する可能性が論理的な問題の多くを示唆したが、ちょうどそのIDはもっとだろう明らかに。私はこれを好み、将来これを行うでしょう。 したがって、私は賞金を得ました。

1

clearメソッドを使用してすべてのエンティティをデタッチしましたか?私はあなたがmergeを行うことができるすべてのエンティティを切り離したと思う。

+2

単一のjsonからすべてのオブジェクトを一度にデシリアライズするときに、それらをすべて分離する必要があります。 – maklemenz

+0

私の場合に役立ちましたが、私はjunitテストから作業していました – tibi

0

誰かがこのエラーが

HHH-7605

を発生したときに変更が4.2.xではバージョンで追加されました、あなたがコミットログオンを見てみることができますより多くの情報を追加するためにHibernate JIRAの中にチケット時間前にオープンEventCacheのためのHibernateのGitの問題に

HHH-7605 Event cache descriptive log messages

を再現するための変更とEventCacheTestのための私は、これが問題を発見するのに役立ちます願っています。

+0

ありがとうございますが、休止状態のアップグレードはオプションではありません。私が使用しているフレームワーク(1.2.xを再生する)は、パッチを適用したバージョンのhibernateを使用しています。単に別の休止状態のバージョンを使用することはできません。 – maklemenz

+0

Dozer mapper Gitのユーザーがこの問題を解決するには、@Transactionalアノテーションをテストクラスに追加してください。https://github.com/DozerMapper/dozer/issues/109 – vzamanillo

+0

ああ、私はあなたがHibernateをアップグレードしなければならないと示唆していませんが、実際の問題を特定するためにテストコードを見ることができます。 – vzamanillo

2

このような振る舞いは、単にJPAやHibernateの範囲外だと思います。そのため、Hibernateは何をすべきか分からないため例外をスローします。私が言いたいのは、GSONのレベル(このような機能をサポートしていないと思われる)に干渉するか、またはDB内のエンティティグラフをマージする直前に、エンティティグラフ内の等しいインスタンスを避けなければならないということです。ここで

関連する問題