objet supprimé serait ré-enregistré en cascade (suppression de l'objet supprimé à partir d'associations)
j'ai les deux entités suivantes:
1 - liste de lecture:
@OneToMany(fetch = FetchType.EAGER, mappedBy = "playlist", orphanRemoval = true, cascade = CascadeType.ALL)
@OrderBy("adOrder")
private Set<PlaylistadMap> PlaylistadMaps = new HashSet<PlaylistadMap>(0);
- CascadeType.Tout : est nécessaire pour sauvegarder et mettre à jour sur la collection PlaylistadMap lors de la sauvegarde ou de la mise à jour de l'entité playlist.
- orphanRemoval = true : est nécessaire pour supprimer l'entité playlist, les références PlaylistadMap doivent être deleteed aussi.
2- PlaylistadMap:
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "fk_playlist", referencedColumnName = "pkid", nullable = false)
private Playlist playlist;
lors de la suppression d'une liste de lecture en utilisant getCurrentSession().delete();
j'obtiens l'exception suivante:
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.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)
veuillez indiquer comment corriger cette exception.
15 réponses
la solution est de faire exactement ce que le message d'exception vous dit:
causé par: org.hiberner.ObjectDeletedException: l'objet supprimé serait sauvegardé de nouveau par cascade ( supprimer l'objet supprimé des associations )
Supprimer l'objet supprimé d'une association (sets, lists, or maps) dans laquelle il se trouve. En particulier, je soupçonne, de PlayList.PlaylistadMaps
. Il ne suffit pas de supprimer le objet, vous devez le retirer de toute collection en cascade qui s'y réfère.
en fait, puisque votre collection a orphanRemoval = true
, vous n'avez pas besoin de la supprimer explicitement. Vous avez juste besoin de l'enlever du plateau.
Problème résolu après avoir changé le FetchType en Lazy
si vous ne savez pas, quelle collection détient votre objet
dans mon cas, il était vraiment difficile d'appliquer la solution de TomAnderson, car je ne savais pas ce qu'était la collection, qui contient un lien vers un objet, alors voici la façon de savoir, quels objets contiennent le lien vers l'objet supprimé: dans le débogueur, vous devez entrer le niveau d'exécution le plus bas avant que l'exception ne soit lancée, il devrait y avoir une variable appelée entityEntry
, donc vous obtenez un objet PersistenceContext
à partir de cette variable: entityEntry.persistenceContext
.
pour moi persistenceContext
était une instance de StatefulPersistenceContext
et cette implémentation a private
champ parentsByChild
, à partir duquel vous pouvez récupérer des informations sur la collection, qui contient l'élément.
j'utilisais Eclipse debugger, donc il était assez difficile de récupérer ce champ privé d'une manière directe, donc j'ai utilisé Detail Formatter
( Comment puis-je regarder des champs privés d'autres objets directement dans le IDE lors du débogage? )
après avoir obtenu cette information, la solution de TomAnderson peut être appliquée.
j'ai pu résoudre cela en écrivant le code ci-dessous. J'ai utilisé executeUpdate à la place .supprimer ()
def publicSupport = caseObj?.client?.publicSupport
if(publicSupport)
PublicSupport.executeUpdate("delete PublicSupport c where c.id = :publicSupportId", [publicSupportId:publicSupport.id])
//publicSupport.delete()
j'ai aussi rencontré ce message d'exception. Pour moi, le problème était différent. Je voulais supprimer un parent.
dans une transaction: J'ai appelé le parent de la base de données. Puis j'ai appelé un élément enfant d'une collection dans le parent. Puis j'ai référencé un champ dans l'Enfant (id) Puis j'ai supprimé le parent. Ensuite, j'ai appelé commettre. J'ai eu la "objet supprimé serait réenregistré" erreur.
il s'avère que j'ai dû faire deux séparés transaction. Je me suis engagé après avoir fait référence au domaine de l'enfant. Puis a démarré une nouvelle propagation pour la suppression.
il n'était pas nécessaire de supprimer les éléments enfant ou vider les collections dans le parent (en supposant orphanRemoval = true.). En fait, cela n'a pas fonctionné.
En somme, cette erreur s'affiche si vous avez une référence à un champ dans un objet enfant lorsque l'objet est supprimé.
C'est une sorte d'Inception qui se passe ici.
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);
}
}
}
un peu comment toutes les solutions ci-dessus n'ont pas fonctionné en hibernation 5.2.10.Final.
mais le réglage de la carte à null comme ci-dessous travaillé pour moi:
playlist.setPlaylistadMaps(null);
une autre solution
je suis complètement d'accord avec redochka et Nikos Paraskevopoulos . Mahmoud Saleh 's réponse d'obtenir sur la question, dans certaines circonstances, pas tout le temps. Dans ma situation, j'ai vraiment besoin de FetchType impatient. De sorte que Pierreux mentionné ci-dessus Je viens juste de retirer d'une liste qui cantian l'objet aussi. Voici mon code:
Rju entité
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 entité
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..........
}
et mon UnderrjuService
@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);
}
.........................
}
parce que j'ai besoin de FetchType pour être EAGER , je supprime toutes les associations en les définissant à (null) et enregistrer l'objet (qui suppriment toute association dans la base de données) puis supprimer!
qui ajoutent quelques millisecondes mais c'est très bien pour moi, s'il y a un meilleur moyen de garder ces MS ajouter votre commentaire ci-dessous..
Espérer que l'aide à quelqu'un :)
j'ai également rencontré cette erreur sur une base de données mal conçue, où il y avait une table Person
avec une seule relation avec une table Code
et une table Organization
avec une seule relation avec la même table Code
. Le Code pourrait s'appliquer à la fois à une organisation et à une personne, selon la situation. L'objet "personne" et L'Objet "Organisation" ont été définis à Cascade=All delete orphans.
quoi toutefois, ni la personne ni l'organisation ne pouvaient supprimer en cascade parce qu'il y avait toujours une autre collection qui avait une référence à elle. Donc peu importe comment il a été supprimé dans le code Java hors de n'importe quel référencement des collections ou des objets que la suppression aurait échoué. La seule façon de l'obtenir pour fonctionner est de le supprimer de la collection j'ai essayé de l'enregistrer puis de les supprimer de la table de Code directement puis enregistrez la collection. De cette façon il n'y a aucune référence à elle.
ce post contient un truc brillant pour détecter où le problème de cascade est:
Essayez de remplacer sur Cascade à l'époque avec Cascade.None()
jusqu'à ce que vous ne recevez pas l'erreur et alors vous avez détecté la cascade causant le problème.
puis résoudre le problème soit par changer la cascade originale à quelque chose d'autre ou en utilisant Tom Anderson réponse.
j'ai eu la même exception, provoquée en essayant de retirer l'enfant de la personne (Person - OneToMany - Kid). Annotation côté personne:
@OneToMany(fetch = FetchType.EAGER, orphanRemoval = true, ... cascade = CascadeType.ALL)
public Set<Kid> getKids() { return kids; }
Sur Kid côté annotation:
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "person_id")
public Person getPerson() { return person; }
donc la solution était de supprimer cascade = CascadeType.ALL
, juste simple: @ManyToOne
sur la classe Kid et il a commencé à travailler comme prévu.
j'avais le même problème. J'essayais de supprimer et d'insérer dans la même transaction. J'ai ajouté theEntityManager.flush();
après theEntityManager.remove(entity);
.
Avait la même erreur. Retirer l'objet du modèle a fait l'affaire.
Code qui montre l'erreur:
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();
}