I run into the "deleted object would be re-saved by cascade" problem when I try to remove a TicketLine object from a collection that belongs to the Ticket class and TicketLine has a OneToOne association to class Reservation.

Tickets defines a collection of TicketLines with the following getter

class Tickets
...
@OneToMany(targetEntity = TicketLine.class, fetch = FetchType.EAGER)
@Fetch(org.hibernate.annotations.FetchMode.SUBSELECT)
@Cascade({org.hibernate.annotations.CascadeType.ALL,  
    org.hibernate.annotations.CascadeType.LOCK,
    org.hibernate.annotations.CascadeType.DELETE_ORPHAN,})
public List<TicketLine> getLines() {
return ticketlines;
}
....

class Reservation defines a OneToOne relationship to TicketLines as follows:

class Reservation 
...
@OneToOne()
@Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.DELETE_ORPHAN})
@JoinColumn(name = "resource_id")
public TicketLine getTicketLine() {
    return ticketLine;
}

Adding a TicketLine object to ticket and a Reservation object to the TicketLine object with

ticket.getLines().add(line);
session.save(ticket);

Reservation res = new Reservation();
res.setTicketLine(m_ticketline);
....
session.save(res);

works as expected. A record in Reservations is being created with the tickets id the resource_id field.

When I remove a line from the collection which has an associated Reservation object I get the following error:

Save ticket failed: org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations): [org.myapp.hibernate.TicketLine#ff8081814a45ebb5014a45ebe4540003]

This error only comes up when there is a Reservation associated with the line. Interestingly, a second try in a new session does not throw an exception but the reservation is not deleted!

Removing a line from the TicketLines collection can happen at many places, i.e. removing the reservation manually is not really an option. I hope this can be managed by Hibernate and I've just done something wrong with the cascade options.

Please help.

1

There are 1 best solutions below

0
On

The exception has gone with the code below. However, the problem is now that line.getReservation() always returns null, although a reservation record exists.

UPDATE: adding the mappedBy attribute

@OneToOne(mappedBy="reservation")

in Reservation solved the last problem. line.getReservation() now also works. Sorry for bothering you.

2nd UPDATE: The previously suggested solution worked as long as the second level cache was valid. After objects had been reloaded the NPE happened again. After some poking in terminology about owning a relationship I came to the following solution that finally works.

class Tickets defines a collection of TicketLines as before.

class TicketLine defines the relationship like so:

class TicketLine
...
private reservation;
...

@OneToOne(mappedBy="ticketline", cascade= CascadeType.ALL, fetch= FetchType.EAGER)
@JoinColumn(name="id", referencedColumnName="resource_id")
@Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.DELETE_ORPHAN})
public Reservation getReservation() {
    return reservation;
}
...

class Reservation defines the OneToOne relationship to TicketLines as follows:

class Reservation 
...
privat TicketLine ticketline;
...
@OneToOne(fetch= FetchType.EAGER)
@JoinColumn(name = "resource_id", insertable=false, updatable=false)
public TicketLine getTicketline() {
    return ticketline;
}
...

Maybe I need to explain that I've named the field resource_id so that it can also be used for additional types of one-to-one relationships in the future. But this should not play a role for now.

Adding a TicketLine object to ticket and a Reservation object to the TicketLine object now goes:

ticket.getLines().add(line);
session.save(ticket);

Reservation res = new Reservation();
/* set property values */
/* line might not yet have an id at that pit of time, but we need one! */
sesssion.save(line);
/* Instead of explicitly setting resource_id I tried to call 
   res.setTicketline(line);
   but this will not set the resource_id as I expected
*/
res.setResource_id(line.getId());
m_ticketline.setReservation(res);
....
/* session.save(res);  
   res is now saved when the ticket containing the line will be saved later*/
....
session.save(ticket);

Saving the line and deleting a line with

ticket.getLines().remove(line);
session.save(ticket);

or deleting all lines (and resarvations) for a ticket along with the ticket with

session.delete(ticket);

all works as expected.

I apologize for the many changes but this was hard to resolve for me and I wanted to provide an answer that is actually working.

Thank you.