web-dev-qa-db-fra.com

l'objet supprimé serait réenregistré en cascade (retirer l'objet supprimé des associations)

j'ai les deux entités suivantes:

1- PlayList:

@OneToMany(fetch = FetchType.EAGER, mappedBy = "playlist", orphanRemoval = true, cascade =   CascadeType.ALL)
@OrderBy("adOrder")
private Set<PlaylistadMap> PlaylistadMaps = new HashSet<PlaylistadMap>(0);
  • CascadeType.ALL : est nécessaire pour enregistrer et mettre à jour la collection PlaylistadMap lors de la sauvegarde ou de la mise à jour de l'entité playlist.
  • orphanRemoval = true : est nécessaire lors de la suppression de l'entité playlist, les références PlaylistadMap doivent également être supprimées.

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 à l'aide de getCurrentSession().delete();, je reçois 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$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)

veuillez indiquer comment résoudre cette exception.

43
Mahmoud Saleh

problème résolu après avoir changé le FetchType en Lazy

21
Mahmoud Saleh

La solution consiste à faire exactement ce que le message d'exception vous indique:

Causée par: org.hibernate.ObjectDeletedException: l'objet supprimé serait réenregistré en cascade ( supprimera l'objet supprimé des associations )

Supprimez l'objet supprimé d'une association (ensembles, listes ou cartes) dans laquelle il se trouve. En particulier, je soupçonne que ce soit de PlayList.PlaylistadMaps. Il ne suffit pas de simplement supprimer l'objet, vous devez le supprimer de toutes les collections en cascade qui s'y réfèrent.

En fait, puisque votre collection a orphanRemoval = true, vous n'avez pas besoin de la supprimer explicitement. Vous avez juste besoin de le retirer de l'ensemble.

40
Tom Anderson

Si vous ne savez pas quelle collection contient votre objet

Dans mon cas, il était très difficile d’appliquer la solution de TomAnderson, car je ne savais pas quelle était la collection, qui contient un lien vers un objet. Voici donc le moyen de savoir quels objets contiennent le lien vers celui qui a été supprimé: Au début du débogueur, vous devez entrer le niveau de pile d'exécution le plus bas avant la levée de l'exception. Il doit exister une variable appelée entityEntry. Vous obtenez donc un objet PersistenceContext à partir de cette variable: entityEntry.persistenceContext.

Pour moi, persistenceContext était une instance de StatefulPersistenceContext et cette implémentation a le champ privateparentsByChild, à partir duquel vous pouvez extraire des informations sur la collection, qui contient l'élément.

J'utilisais le débogueur Eclipse, il était donc difficile de récupérer ce champ privé de manière simple. J'ai donc utilisé Detail Formatter ( Comment puis-je regarder les champs privés d'autres objets directement dans IDE lors du débogage? )

Après avoir obtenu ces informations, la solution de TomAnderson peut être appliquée.

5
Dmitry Ginzburg

J'ai pu résoudre ce problème en écrivant le code ci-dessous. J'ai utilisé executeUpdate au lieu de .delete ()

def publicSupport = caseObj?.client?.publicSupport
        if(publicSupport)
            PublicSupport.executeUpdate("delete PublicSupport c where c.id = :publicSupportId", [publicSupportId:publicSupport.id])
            //publicSupport.delete()
2
user742102

J'ai aussi rencontré ce message d'exception… .. Pour moi, le problème était différent… .. Je voulais supprimer un parent.

En une transaction:

  • J'ai d'abord appelé le parent de la base de données.
  • Ensuite, j'ai appelé un élément enfant d'une collection du parent. 
  • Ensuite, j'ai référencé un champ dans l'enfant (id)
  • Puis j'ai supprimé le parent.
  • Puis j'ai appelé commit.
  • J'ai l'erreur "l'objet supprimé sera sauvé".

Il s’avère que j’ai dû faire deux transactions distinctes… j’ai commis après avoir référencé le champ dans l’enfant. Puis a commencé un nouveau commit pour la suppression. 

Il n'était pas nécessaire de supprimer les éléments enfants ou de vider les collections du parent (en supposant que orphanRemoval = true.). En fait, cela n'a pas fonctionné.

En résumé, cette erreur apparaît si vous avez une référence à un champ dans un objet enfant lorsque cet objet est en cours de suppression.

2
Jake

Type de création 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);
            }
        }
    }
1
Ben Tennyson

Certaines des solutions ci-dessus n’ont pas fonctionné dans la version 5.2.10.Final d’Hibernate.

Mais définir la carte sur null comme ci-dessous a fonctionné pour moi:

playlist.setPlaylistadMaps(null);
1
KayV

Une autre solution de contournement

Je suis tout à fait d’accord avec redochka et Nikos Paraskevopoulos . Mahmoud Saleh réponse de/surmonter la question dans certaines circonstances pas à chaque fois. Dans ma situation, j'ai vraiment besoin de fetchtype Eager. Donc, en tant que Stony mentionné ci-dessus .__, je viens de supprimer d'une liste qui cantian l'objet aussi Voici mon code:

Entité 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;
.........
}

Entité sous-jacente

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);

    }
     .........................
}
1
Frank

Parce que j'ai besoin de FetchType d'êtreD&EACUTE;SIREUX, je supprime toutes les associations en les définissant sur (null) et enregistre l'objet (qui supprime toute association dans la base de données), puis le supprime!

Cela ajoute quelques millisecondes, mais ça me convient, s’il existe un meilleur moyen de conserver ces MS, ajoutez votre commentaire ci-dessous.

J'espère que ça aide quelqu'un :)

0
Smile2Life

Ce problème se produira si vous supprimez en utilisant PlaylistadMap modal au lieu de PlayList . Dans ce cas, FetchType = Lazy n'est pas la bonne option. Il ne lève aucune exception, mais seules les données de PlaylistadMap seront supprimées. Les données de PlayList resteront dans la table. Vérifiez cela aussi.

0
RAGINROSE

J'ai eu la même exception, causée en essayant de retirer l'enfant de la personne (Person - OneToMany - Kid) . Annotation du côté de la personne:

@OneToMany(fetch = FetchType.EAGER, orphanRemoval = true, ... cascade    = CascadeType.ALL)
public Set<Kid> getKids() {    return kids; }

Sur l'annotation côté enfant:

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "person_id")
public Person getPerson() {        return person;    }

La solution a donc été de supprimer cascade = CascadeType.ALL, simplement: @ManyToOne dans la classe Kid et cela a commencé à fonctionner comme prévu.

0
Oleh Podolyan

J'ai également rencontré cette erreur sur une base de données mal conçue, où il y avait une table Person avec une relation one2many avec une table Code et une table Organization avec une relation one2many avec la même table Code. Le code pourrait s'appliquer à la fois à une organisation et à une personne, selon la situation. Les objets Personne et Organisation ont été définis sur Cascade = All delete orphans.  

Cette utilisation surchargée de la table Code a toutefois eu pour conséquence que ni la Personne ni l’Organisation ne pouvaient effectuer une suppression en cascade car il y avait toujours une autre collection qui y faisait référence. Ainsi, quelle que soit la manière dont elle a été supprimée dans le code Java à partir de collections ou d'objets référencés, la suppression échouera. Le seul moyen de le faire fonctionner était de le supprimer de la collection que j'essayais de sauvegarder, puis de le supprimer du tableau Code directement, puis de sauvegarder la collection. De cette façon, il n'y avait aucune référence à cela.

0
Uncle Iroh

Eu la même erreur. Retrait de 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();
}
0
Martin Pfeffer

J'avais le même problème. J'essayais de supprimer et insérer dans la même transaction. J'ai ajouté theEntityManager.flush(); après theEntityManager.remove(entity);.

0
Jai

Ce message contient une astuce brillante pour détecter où se situe le problème de cascade:
Essayez de remplacer le cascade à l'heure avec Cascade.None() jusqu'à ce que vous n'ayez pas l'erreur et que vous ayez détecté la cascade à l'origine du problème.

Ensuite, résolvez le problème soit en en modifiant la cascade originale, soit en utilisant Tom Anderson answer.

0
Morten Holmgaard