JPAカスケード永続化および分離されたエンティティへの参照はPersistentObjectExceptionをスローします。どうして?
新しいFooを永続化すると、新しいBarまたは既存のBarのいずれかへの参照を取得できます。既存のBarが切り離されると、JPAプロバイダ(Hibernate)は次の例外をスローします。Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: com.example.Bar
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:102)
at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:636)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:628)
at org.hibernate.engine.EJB3CascadingAction$1.cascade(EJB3CascadingAction.java:28)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:291)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:239)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:192)
at org.hibernate.engine.Cascade.cascade(Cascade.java:153)
at org.hibernate.event.def.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:454)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:288)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130)
at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:49)
at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:154)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:110)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61)
at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:645)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:619)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:623)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:220)
... 112 more
Barへの参照が管理(添付)されているか、関係のPERSISTカスケード、すべて正常に動作します。
どちらの解決法も100%満足です。カスケードを削除しても、私は明らかにFooを新しいBarへの参照で永続させることはできません。 Barを管理するためのリファレンスを作成するには、これを永続化する前に次のようなコードが必要です。
if (foo.getBar().getID() != null && !entityManager.contains(foo.getBar())) {
foo.setBar(entityManager.merge(foo.getUBar()));
}
entityManager.persist(foo);
単一のBarの場合、これは大きな問題ではないかもしれませんが、このようにすべてのプロパティを考慮する必要があれば、最初はORMを使用する理由を打ち負かしていると思われるかなり恐ろしいコードで始まります。私は、JDBCを使って手動でオブジェクトグラフを手動で保持することもできます。
JPAが持っている唯一のことは、既存のBarリファレンスが与えられたときにIDを取得し、それをFooを保持するテーブルの列に挿入することです。 Barが接続されているときはこれが正確ですが、Barが切り離されたときは例外がスローされます。
私の質問は、なぜバーが取り付けられる必要がありますか? Barインスタンスがデタッチ状態からアタッチ状態に移行するときに、そのIDは変更されず、そのIDがここで必要な唯一のものであるように思われます。
おそらくこれはHibernateのバグですか、何か不足していますか?
カスケードからPERSISTを削除して、if(id == null){em.persiste(foo.getBar())}を確認してください。 – amorfis
実際、それは実際には少しシンプルになります。提案していただきありがとうございます。 –
もちろん、if文を少し単純にしても、永続化するコードはオブジェクトグラフ全体を辿る必要があります。これは避けようとしています。 –