次の2つのエンティティがあります。
1-プレイリスト:
_@OneToMany(fetch = FetchType.EAGER, mappedBy = "playlist", orphanRemoval = true, cascade = CascadeType.ALL)
@OrderBy("adOrder")
private Set<PlaylistadMap> PlaylistadMaps = new HashSet<PlaylistadMap>(0);
_
2- PlaylistadMap:
_@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "fk_playlist", referencedColumnName = "pkid", nullable = false)
private Playlist playlist;
_
getCurrentSession().delete();
を使用してプレイリストを削除すると、次の例外が発生します。
_org.springframework.dao.InvalidDataAccessApiUsageException: deleted object would be re-saved by cascade (remove deleted object from associations): [com.xeno.advertisingsuite.web.domain.PlaylistadMap#6]; nested exception is org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations): [com.xeno.advertisingsuite.web.domain.PlaylistadMap#6]
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.Java:657)
at org.springframework.orm.hibernate3.HibernateTransactionManager.convertHibernateAccessException(HibernateTransactionManager.Java:793)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.Java:664)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.Java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.Java:723)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.Java:393)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.Java:120)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.Java:202)
at $Proxy54.deletePlayList(Unknown Source)
at com.xeno.advertisingsuite.web.beans.PlayListBean.deletePlaylist(PlayListBean.Java:282)
at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:39)
at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:25)
at Java.lang.reflect.Method.invoke(Method.Java:597)
at org.Apache.el.parser.AstValue.invoke(AstValue.Java:262)
at org.Apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.Java:278)
at com.Sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.Java:105)
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.Java:88)
... 103 more
Caused by: org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations): [com.xeno.advertisingsuite.web.domain.PlaylistadMap#6]
at org.hibernate.impl.SessionImpl.forceFlush(SessionImpl.Java:1220)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.Java:188)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.Java:117)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.Java:93)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.Java:677)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.Java:669)
at org.hibernate.engine.CascadingAction$5.cascade(CascadingAction.Java:252)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.Java:392)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.Java:335)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.Java:204)
at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.Java:425)
at org.hibernate.engine.Cascade.cascadeCollection(Cascade.Java:362)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.Java:338)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.Java:204)
at org.hibernate.engine.Cascade.cascade(Cascade.Java:161)
at org.hibernate.event.def.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.Java:154)
at org.hibernate.event.def.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.Java:145)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.Java:88)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.Java:50)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.Java:1206)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.Java:375)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.Java:137)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.Java:656)
_
この例外を修正する方法を教えてください。
FetchTypeをLazyに変更した後に解決した問題
解決策は、例外メッセージが示す内容を正確に実行することです。
原因:org.hibernate.ObjectDeletedException:削除されたオブジェクトはカスケードによって再保存されます(関連付けから削除されたオブジェクトを削除)
削除されたオブジェクトを、それが属する関連付け(セット、リスト、またはマップ)から削除します。特に、PlayList.PlaylistadMaps
。オブジェクトを単に削除するだけでは十分ではありません。オブジェクトを参照するカスケードコレクションから削除する必要があります。
実際、コレクションにはorphanRemoval = true
、明示的に削除する必要はありません。セットから削除するだけです。
私の場合、TomAndersonのソリューションを適用するのは非常に困難でした。コレクションとは何か、オブジェクトへのリンクを保持しているかわからなかったので、ここでは、削除されたオブジェクトへのリンクを保持しているオブジェクトを知る方法があります:デバッガーは、例外がスローされる前に最低の実行スタックレベルに入る必要があります。entityEntry
という変数があるはずです。そのため、この変数からPersistenceContext
オブジェクトを取得します:entityEntry.persistenceContext
。
私にとってpersistenceContext
はStatefulPersistenceContext
のインスタンスであり、この実装にはprivate
フィールドparentsByChild
があります。このフィールドから、要素を含むコレクションに関する情報を取得できます。
私はEclipseデバッガを使用していたので、このプライベートフィールドをまっすぐに取得するのはちょっと難しいので、Detail Formatter
を使用しました( 他のオブジェクトのプライベートフィールドをIDEデバッグ時? )
この情報を取得した後、TomAndersonのソリューションを適用できます。
以下のコードを書くことでこれを解決できました。 .delete()の代わりにexecuteUpdateを使用しました
def publicSupport = caseObj?.client?.publicSupport
if(publicSupport)
PublicSupport.executeUpdate("delete PublicSupport c where c.id = :publicSupportId", [publicSupportId:publicSupport.id])
//publicSupport.delete()
上記のすべてのソリューションがhibernate 5.2.10.Finalで機能しなかった方法。
しかし、以下のようにマップをnullに設定するとうまくいきました:
playlist.setPlaylistadMaps(null);
この例外メッセージも発生しました。私にとって問題は異なっていました。親を削除したかった。
1つのトランザクションで:
私は2つの別々のトランザクションをしなければならなかったことがわかりました。子のフィールドを参照した後、コミットしました。次に、削除のための新しいコミットを開始しました。
子要素を削除したり、親のコレクションを空にする必要はありませんでした(orphanRemoval = true
。)。実際、これは機能しませんでした。
要するに、このエラーは、そのオブジェクトが削除されているときに子オブジェクトのフィールドへの参照がある場合に表示されます。
ここで起こっているインセプションの種類。
for (PlaylistadMap playlistadMap : playlistadMaps) {
PlayList innerPlayList = playlistadMap.getPlayList();
for (Iterator<PlaylistadMap> iterator = innerPlayList.getPlaylistadMaps().iterator(); iterator.hasNext();) {
PlaylistadMap innerPlaylistadMap = iterator.next();
if (innerPlaylistadMap.equals(PlaylistadMap)) {
iterator.remove();
session.delete(innerPlaylistadMap);
}
}
}
redochka および Nikos Paraskevopoulos に完全に同意します。 Mahmoud Saleh の答えは、毎回ではなく、状況によっては問題を乗り越えます。私の状況では、Eager fetchtypeが本当に必要です。したがって、上記の Stony のように、オブジェクトをカンティアンにするリストからも削除しました。ここに私のコードがあります:
Rjuエンティティ
public class Rju extends AbstractCompany implements Serializable {
/**
*
*/
private static final long serialVersionUID = 4294142403795421252L;
//this field just duplicates @Column(name="callname") and serves for mapping to Rju fullname field
@Column(name = "fullname")
private String namerju;
@NotEmpty
@Column(name = "briefname")
private String briefname;
@LazyCollection(LazyCollectionOption.FALSE)
@OneToMany(cascade = CascadeType.ALL, mappedBy = "otd")
private Collection<Vstan> vStanCollection;
// @LazyCollection(LazyCollectionOption.FALSE)
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "rju", orphanRemoval = true)
private Collection<Underrju> underRjuCollection;
.........
}
Underrjuエンティティ
public class Underrju extends AbstractCompany implements Serializable {
/**
*
*/
private static final long serialVersionUID = 2026147847398903848L;
@Column(name = "name")
private String name;
@NotNull
@Valid
@JoinColumn(name = "id_rju", referencedColumnName = "id")
@ManyToOne(optional = false)
private Rju rju;
......getters and setters..........
}
and myUnderrjuService
@Service("underrjuService")
@Transactional
public class UnderRjuServiceImpl implements UnderRjuService {
@Autowired
private UnderRjuDao underrjuDao;
.............another methods........................
@Override
public void deleteUnderrjuById(int id) {
Underrju underrju=underrjuDao.findById(id);
Collection<Underrju> underrjulist=underrju.getRju().getUnderRjuCollection();
if(underrjulist.contains(underrju)) {
underrjulist.remove(underrju);
}
underrjuDao.delete(id);
}
.........................
}
FetchTypeを[〜#〜] eager [〜#〜]にする必要があるため、すべての関連付けを(null)に設定して削除し、オブジェクトを(削除する)データベース内のすべての関連付け)削除します!
それは数ミリ秒を追加しますが、それらのMSにコメントを追加するより良い方法があれば、私にとっては問題ありません。
誰かを助けることを願っています:)
この問題は、PlayListの代わりにPlaylistadMapモーダルを使用して削除した場合に発生します。この場合、FetchType = Lazyは適切なオプションではありません。例外はスローされませんが、PlaylistadMapのデータのみが削除され、PlayListのデータはテーブルに残ります。それも確認してください。
私は同じ例外を持っていた、人から子供を削除しようとしたときに引き起こされた(Person-OneToMany-Kid)。人の側の注釈:
@OneToMany(fetch = FetchType.EAGER, orphanRemoval = true, ... cascade = CascadeType.ALL)
public Set<Kid> getKids() { return kids; }
子供側の注釈について:
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "person_id")
public Person getPerson() { return person; }
そのため、解決策はcascade = CascadeType.ALL
を削除することで、Kidクラスの@ManyToOne
を削除するだけで、期待どおりに機能し始めました。
また、設計が不適切なデータベースでこのエラーに遭遇し、Person
テーブルとのone2many関係を持つCode
テーブルと、one2many関係を持つOrganization
テーブルがありました同じCode
テーブル。コードは、状況に応じて組織と個人の両方に適用できます。 PersonオブジェクトとOrganizationオブジェクトの両方がCascade = All delete orphansに設定されていました。
ただし、コードテーブルのこのオーバーロードされた使用からは、PersonもOrganizationも参照を保持する別のコレクションが常に存在するため、カスケード削除できませんでした。したがって、どのコレクションを参照するコレクションやオブジェクトからJavaコードを削除しても、削除は失敗します。それを機能させる唯一の方法は、コレクションから削除することでした。保存してからCodeテーブルから直接削除してからコレクションを保存しようとすると、その参照はありませんでした。
同じエラーがありました。モデルからオブジェクトを削除するのがうまくいきました。
間違いを示すコード:
void update() {
VBox vBox = mHboxEventSelection.getVboxSelectionRows();
Session session = HibernateUtilEventsCreate.getSessionFactory().openSession();
session.beginTransaction();
HashMap<String, EventLink> existingEventLinks = new HashMap<>();
for (EventLink eventLink : mEventProperty.getEventLinks()) {
existingEventLinks.put(eventLink.getEvent().getName(), eventLink);
}
mEventProperty.setName(getName());
for (Node node : vBox.getChildren()) {
if (node instanceof HBox) {
JFXComboBox<EventEntity> comboBoxEvents = (JFXComboBox<EventEntity>) ((HBox) node).getChildren().get(0);
if (comboBoxEvents.getSelectionModel().getSelectedIndex() == -1) {
Log.w(TAG, "update: Invalid eventEntity collection");
}
EventEntity eventEntity = comboBoxEvents.getSelectionModel().getSelectedItem();
Log.v(TAG, "update(" + mCostType + "): event-id=" + eventEntity.getId() + " - " + eventEntity.getName());
String split = ((JFXTextField) (((HBox) node).getChildren().get(1))).getText();
if (split.isEmpty()) {
split = "0";
}
if (existingEventLinks.containsKey(eventEntity.getName())) {
// event-link did exist
EventLink eventLink = existingEventLinks.get(eventEntity.getName());
eventLink.setSplit(Integer.parseInt(split));
session.update(eventLink);
existingEventLinks.remove(eventEntity.getName(), eventLink);
} else {
// event-link is a new one, so create!
EventLink link1 = new EventLink();
link1.setProperty(mEventProperty);
link1.setEvent(eventEntity);
link1.setCreationTime(new Date(System.currentTimeMillis()));
link1.setSplit(Integer.parseInt(split));
eventEntity.getEventLinks().add(link1);
session.saveOrUpdate(eventEntity);
}
}
}
for (Map.Entry<String, EventLink> entry : existingEventLinks.entrySet()) {
Log.i(TAG, "update: will delete link=" + entry.getKey());
EventLink val = entry.getValue();
mEventProperty.getEventLinks().remove(val); // <- remove from model
session.delete(val);
}
session.saveOrUpdate(mEventProperty);
session.getTransaction().commit();
session.close();
}
私は同じ問題を抱えていました。同じトランザクションで削除と挿入を試みました。 theEntityManager.flush();
の後にtheEntityManager.remove(entity);
を追加しました。
この投稿には、カスケードの問題がどこにあるかを検出するための素晴らしいトリックが含まれています:
エラーが発生せず、問題の原因となっているカスケードを検出するまで、CascadeをCascade.None()
に置き換えてみてください。 。
次に、元のカスケードを他のカスケードに変更するか、Tom Anderson回答を使用して問題を解決します。