org.hibernate.ObjectDeletedException: удаленный объект будет повторно сохранен каскадно, когда объекты коллекции имеют ассоциацию один к одному

Я сталкиваюсь с проблемой «удаленный объект будет повторно сохранен каскадно», когда пытаюсь удалить объект TicketLine из коллекции, принадлежащей классу Ticket, а TicketLine имеет ассоциацию OneToOne с классом Reservation.

Tickets определяет коллекцию TicketLines со следующим геттером

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

класс Reservation определяет отношение OneToOne к TicketLines следующим образом:

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

Добавление объекта TicketLine к билету и объекта Reservation к объекту TicketLine с помощью

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

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

работает как положено. Запись в Reservations создается с идентификатором тикета в поле resource_id.

Когда я удаляю строку из коллекции, которая имеет связанный объект Reservation, я получаю следующую ошибку:

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

Эта ошибка возникает только в том случае, если с линией связано резервирование. Интересно, что вторая попытка в новом сеансе не вызывает исключение, но резервирование не удаляется!

Удаление строки из коллекции TicketLines может происходить во многих местах, т. е. удаление резервирования вручную на самом деле не вариант. Я надеюсь, что Hibernate может управлять этим, и я только что сделал что-то не так с параметрами каскада.

Пожалуйста помоги.


person arcasys    schedule 14.12.2014    source источник
comment
Можете обновить пост с кодом, удаляющим строку из коллекции? У вас также есть код для удаления объекта линии?   -  person Andy Dufresne    schedule 14.12.2014
comment
Пожалуйста, обратитесь к моему ответу. Спасибо.   -  person arcasys    schedule 14.12.2014


Ответы (1)


Исключение пошло с кодом ниже. Однако теперь проблема заключается в том, что line.getReservation() всегда возвращает null, хотя запись резервирования существует.

ОБНОВЛЕНИЕ: добавление атрибута mappedBy

@OneToOne(mappedBy="reservation")

в резервации решили последнюю проблему. line.getReservation() теперь также работает. Извините за беспокойство.

2-е ОБНОВЛЕНИЕ: ранее предложенное решение работало до тех пор, пока был действителен кеш второго уровня. После перезагрузки объектов снова возник NPE. Покопавшись в терминологии владения отношениями, я пришел к следующему решению, которое, наконец, работает.

Класс Tickets, как и прежде, определяет коллекцию TicketLines.

класс TicketLine определяет отношение следующим образом:

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

Класс Reservation определяет отношение OneToOne к TicketLines следующим образом:

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

Возможно, мне нужно объяснить, что я назвал поле resource_id, чтобы его также можно было использовать для дополнительных типов отношений один-к-одному в будущем. Но это пока не должно играть роли.

Теперь добавление объекта TicketLine в билет и объекта Reservation в объект TicketLine происходит следующим образом:

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

Сохранение строки и удаление строки с помощью

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

или удаление всех строк (и перебронирований) для билета вместе с билетом с

session.delete(билет);

все работает как положено.

Я прошу прощения за множество изменений, но мне было трудно решить эту проблему, и я хотел дать ответ, который действительно работает.

Спасибо.

person arcasys    schedule 14.12.2014