57

I have the following two entities:

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: is needed for save and update on the PlaylistadMap collection when saving or updating the playlist entity.
  • orphanRemoval = true: is needed when deleting the playlist entity, the PlaylistadMap references should be deleteed too.

2- PlaylistadMap:

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "fk_playlist", referencedColumnName = "pkid", nullable = false)
private Playlist playlist;

when deleting a playlist by using getCurrentSession().delete(); i am getting the following exception:

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)

please advise how to fix this exception.

Topera
  • 12,223
  • 15
  • 67
  • 104
Mahmoud Saleh
  • 33,303
  • 119
  • 337
  • 498

20 Answers20

61

The solution is to do exactly what the exception message tells you:

Caused by: org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations)

Remove the deleted object from an associations (sets, lists, or maps) that it is in. In particular, i suspect, from PlayList.PlaylistadMaps. It's not enough to just delete the object, you have to remove it from any cascading collections which refer to it.

In fact, since your collection has orphanRemoval = true, you don't need to delete it explicitly. You just need to remove it from the set.

Tom Anderson
  • 46,189
  • 17
  • 92
  • 133
  • 1
    i tried to remove the entity from the set by clearing the set before delete as follows: `playlist.getPlaylistadMaps().clear(); playlist = (Playlist) getCurrentSession().merge(playlist); super.delete(playlist);` but it doesn't work – Mahmoud Saleh Jul 25 '12 at 12:58
  • i tried to remove the entity to be deleted from the collection before delete as mentioned here http://stackoverflow.com/questions/3068817/hibernate-triggering-constraint-violations-using-orphanremoval but it doesn't work still getting same exception – Mahmoud Saleh Jul 26 '12 at 10:29
  • I just removed from a list which cantian the object. that solved my issue. – Stony Aug 21 '14 at 06:01
  • 5
    Intellij has a new feature called "Show referring objects" and does exactly as it suggests, I could fix this by setting the object reference to null. – atavakoli Apr 21 '15 at 19:21
  • 1
    This kind of worked for me. I was having a OneToOne mapping with the referencing object. ObjectToDelete.getReferencingObject().setObjectToDelete(null); – Paras Jain Jun 13 '17 at 08:51
  • @Tom Anderson what if we are trying to create an association and it depends on the column, whose value we want to delete when corresponding value is deleted in parent table. – sql_dummy Feb 09 '18 at 05:56
26

problem solved after changing the FetchType to Lazy

Mahmoud Saleh
  • 33,303
  • 119
  • 337
  • 498
  • 25
    Hibernate is weird sometimes. – Tom Anderson Jul 26 '12 at 12:37
  • Wow. I was having an issue for hours trying to use **nHibernate** to do a many-to-many association (with meta data using a _joining_ class) and in the end this turned out be my problem too. Thank you! – Ryan Bosinger Aug 01 '12 at 21:21
  • 8
    is there any other solution to it, making FetchType Lazy is really not an option. – Sikorski Dec 12 '12 at 13:17
  • @Sikorski remove the child entity from the list where is contained and then apply the `delete(entity)` – Luiggi Mendoza Jan 10 '13 at 21:27
  • Lazy sometimes is not an option. Do not forget to override hashcode and equals. Hibernate really sucks. – redochka Feb 04 '13 at 19:09
  • 2
    @Sikorski - I was running into the same issue but followed the advice [here](http://gullele.wordpress.com/2010/08/04/deleted-object-would-be-re-saved-by-cascade-remove-deleted-object-from-associations/) and it worked fine for me. – Vini Jun 06 '13 at 18:22
  • This is not a solution to the problem, rather an opportunistic workaround. For (a) LAZY cannot always be an option - as mentioned above and (b) if the LAZY relationship gets loaded, you will face the same error, I believe. – Nikos Paraskevopoulos Oct 31 '16 at 16:33
9

If you don't know, which collection holds your object

In my case it was really hard to apply TomAnderson's solution, since I didn't know what is the collection, which holds a link to an object, so here's the way to know, which objects holds the link to the deleted one: in the debugger you should enter the lowest execution stack level before the exception is thrown, there should be a variable called entityEntry, so you get a PersistenceContext object from this variable: entityEntry.persistenceContext.

For me persistenceContext was an instance of StatefulPersistenceContext and this implementation has private field parentsByChild, from which you can retrieve information about the collection, which contains the element.

I was using Eclipse debugger, so it was kinda hard to retrieve this private field in a straight way, so I used Detail Formatter (How can I watch private fields of other objects directly in the IDE when debugging?)

After getting this information, TomAnderson's solution can be applied.

Community
  • 1
  • 1
Dmitry Ginzburg
  • 7,391
  • 2
  • 37
  • 48
3

Some how all the above solutions did not worked in hibernate 5.2.10.Final.

But setting the map to null as below worked for me:

playlist.setPlaylistadMaps(null);
KayV
  • 12,987
  • 11
  • 98
  • 148
2

I was able to resolve this by writing the code below. I used executeUpdate instead of .delete()

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

I encountered this exception message as well. For me the problem was different. I wanted to delete a parent.

In one transaction:

  • First I called up the parent from the database.
  • Then I called a child element from a collection in the parent.
  • Then I referenced one field in the child (id)
  • Then I deleted the parent.
  • Then I called commit.
  • I got the "deleted object would be resaved" error.

It turns out that I had to do two separate transactions. I committed after referencing the field in the child. Then started a new commit for the delete.

There was no need to delete the child elements or empty the collections in the parent (assuming orphanRemoval = true.). In fact, this didn't work.

In sum, this error appears if you have a reference to a field in a child object when that object is being deleted.

Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228
Jake
  • 4,322
  • 6
  • 39
  • 83
2

I was having same issue. I was trying to delete and insert in the same transaction. I added theEntityManager.flush(); after theEntityManager.remove(entity);.

Bryan
  • 1,335
  • 1
  • 16
  • 32
Jai
  • 21
  • 1
2

Another workaround

I completely agree with redochka and Nikos Paraskevopoulos. Mahmoud Saleh's answer get over the issue in some circumstances not every time. In my situation I really need Eager fetchtype. So as Stony mentioned above I just removed from a list which cantian the object too. Here is my code:

Rju entity

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 entity

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

    }
     .........................
}
Frank
  • 178
  • 1
  • 12
1

Kind of Inception going on here.

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);
            }
        }
    }
Ben Tennyson
  • 637
  • 6
  • 18
0

Because i need FetchType to be EAGER, i remove all associations by setting them to (null) and save the object (that remove all association in the database) then delete it!

That add some milliseconds but it's fine for me, if there better way to keep those MS add your comment bellow..

Hope that help someone :)

Smile2Life
  • 1,921
  • 3
  • 16
  • 30
0

I also ran into this error on a badly designed database, where there was a Person table with a one2many relationship with a Code table and an Organization table with a one2many relationship with the same Code table. The Code could apply to both an Organization and Or a Person depending on situation. Both the Person object and the Organization object were set to Cascade=All delete orphans.

What became of this overloaded use of the Code table however was that neither the Person nor the Organization could cascade delete because there was always another collection that had a reference to it. So no matter how it was deleted in the Java code out of whatever referencing collections or objects the delete would fail. The only way to get it to work was to delete it out of the collection I was trying to save then delete it out of the Code table directly then save the collection. That way there was no reference to it.

Uncle Iroh
  • 5,748
  • 6
  • 48
  • 61
0

This post contains a brilliant trick to detect where the cascade problem is:
Try to replace on Cascade at the time with Cascade.None() until you do not get the error and then you have detected the cascade causing the problem.

Then solve the problem either by changing the original cascade to something else or using Tom Anderson answer.

Community
  • 1
  • 1
Morten Holmgaard
  • 7,484
  • 8
  • 63
  • 85
0

I had the same exception, caused when attempting to remove the kid from the person (Person - OneToMany - Kid). On Person side annotation:

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

On Kid side annotation:

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

So solution was to remove cascade = CascadeType.ALL, just simple: @ManyToOne on the Kid class and it started to work as expected.

0

Had the same error. Removing the object from the model did the trick.

Code which shows the mistake:

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();
}
Martin Pfeffer
  • 12,471
  • 9
  • 59
  • 68
0

This problem will happen if you delete using PlaylistadMap modal instead of PlayList. In this case FetchType = Lazy is not the right option. It will not throw any exception but only data from PlaylistadMap will get deleted, the data in PlayList will remain in the table. Check that also.

Maicon Mauricio
  • 2,052
  • 1
  • 13
  • 29
RAGINROSE
  • 694
  • 8
  • 13
0

I just to solve this problem.

  1. I set to null the value of list
  2. I saved the object (It worked)
  3. I set the new data to the object
  4. I resaved the object
  5. It works.!
Jan Sršeň
  • 1,045
  • 3
  • 23
  • 46
0

You need to remove association on the mapping object:

playList.getPlaylistadMaps().setPlayList(null);
session.delete(playList);
0

The Solution is to 'break' the relationship between the objects, and then try to delete again. The answer is in your log:

(remove deleted object from associations): [com.xeno.advertisingsuite.web.domain.PlaylistadMap#6]

Explain: what?(remove association) Where?[PlaylistadMap object with id#6]

Martin Brisiak
  • 3,872
  • 12
  • 37
  • 51
Ron
  • 1
-1
cascade = { CascadeType.ALL }, fetch = FetchType.LAZY
Bhavin Bhadani
  • 22,224
  • 10
  • 78
  • 108
chris77
  • 16
  • 1
-1

I am adding a new solution. Yes it is correct that you must remove all references to the object before doing session.remove(object).

This is because you are probably using eager loading, but sometimes your code won't work without it.

Then these guys say all you have to do is find the object but this is not so clear or easy to do. If you are using beans inside an MVC it can be a true mind F.

My solution?

In whatever method you are using do session.clear() right before session.remove(object)

This worked like a charm.

BMET1

BMET1
  • 31
  • 1
  • Do you like data loss? From clear() documentation: Completely clear the session. Evict all loaded instances and cancel all pending saves, updates and deletions. Do not close open iterators or instances of ScrollableResults. – Thor Hovden Nov 25 '22 at 15:15
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 25 '22 at 16:30
  • 1
    @Thor Hovden I didn't get any data loss. The code worked fine and I tested it many times. I do concede that later on I found a different way to do things that got around the error all together without having to do session.clear(). – BMET1 Nov 26 '22 at 05:52