Каскадное обновление / удаление JPA 2.0
У меня есть отношение nn, сопоставленное с этими 3 объектами:
@Entity
public class ApplicatifDo {
.....
@OneToMany(cascade = CascadeType.ALL, mappedBy = "applicatifDo", fetch = FetchType.EAGER, orphanRemoval = true)
private Set<ApplicatifTerminalDo> applicatifTerminalSet;
.....
}
@Entity
public class ApplicatifTerminalDo {
......
@ManyToOne
@JoinColumn(name = "idApplicatif", nullable = false)
private ApplicatifDo applicatifDo;
@ManyToOne
@JoinColumn(name = "idTerminal", nullable = false)
private TerminalDo terminalDo;
@Column
private String remarques;
......
}
@Entity
public class TerminalDo {
......
@OneToMany(cascade = CascadeType.ALL, mappedBy = "terminalDo", fetch = FetchType.EAGER, orphanRemoval = true)
private Set<ApplicatifTerminalDo> applicatifTerminalSet;
......
}
Я пытаюсь выполнить тест, в котором у меня есть сохраненный ApplicatifDo, в котором содержится множество ApplicatifTerminalDo в своем наборе, и я изменяю некоторые из них, удаляю другие, добавляю новые в этом наборе:
modifyRemarques(firstElement(applicatifDo.getApplicatifTerminalSet()));
applicatifDo.getApplicatifTerminalSet.add(anotherApplicatifTerminal);
applicatifDo.getApplicatifTerminalSet.remove(onceApplicatifTerminal);
Затем, когда я объединяю это в моей БД, в моей соединительной таблице ApplicatifTerminal я вижу изменение "Remarques", а также новые сущности ApplicatifTerminal, но удаление не работает, и сущности, которые должны быть удалены, все еще присутствует в моей таблице соединений (и я использую orphanRemoval).
И я не получаю ошибку в консоли, когда я тестирую это, но все же объекты удаления больше не должны быть в БД.
PS: я использовал один и тот же метод для отношения 1-n, и каскадирование всех типов изменений в содержавшемся множестве сущностей в родительской сущности работало хорошо (включая удаление).
Обновить:
Я пытался удалить OnceApplicatifTerminal из TerminalDo, как сказал Крис, но все равно не работает. Вот код:
Iterator<ApplicatifTerminalDo> iterator = applicatifDo
.getApplicatifTerminalSet().iterator();
boolean first = true;
while (iterator.hasNext()) {
ApplicatifTerminalDo element = iterator.next();
if (!first) {
element.setRemarques("remarques updated");
} else {
iterator.remove();
element.getTerminalDo().setApplicatifTerminalSet(
applicatifDo.getApplicatifTerminalSet());
first = false;
}
}
Здесь я пытаюсь удалить первый ApplicatifTerminalDo из списка и обновить значение столбца для других. И когда я объединяюсь, значения меняются, но удаление не работает, даже если я получаю TerminalDo для удаления, поместите обновленный Набор ApplicatfTerminal.
Можно ли добиться того, что я хочу сделать? Как лучше всего обновлять / удалять строки из таблицы соединений, созданной лично?
Пожалуйста, помогите, я не понимаю почему.
1 ответ
Вы ожидаете, что удаление сирот вступит в силу, потому что вы разыменовали OnceApplicatifTerminal, и хотите OnceApplicatifTerminal.
Удаление сирот имеет свои недостатки, на которые намекают, когда оно называется частной собственностью в других ORM: объект действительно должен принадлежать только частному лицу, что здесь не так. Вы сталкиваетесь с проблемами, когда вы звоните applicatifDo.getApplicatifTerminalSet.remove(onceApplicatifTerminal);
потому что существует экземпляр TerminalDo, который также ссылается на этот экземпляр OnceApplicatifTerminal. В JPA разрешено использование кэширования, поэтому, если этот TerminalDo-> OnceApplicatifTerminal также не будет очищен в ваших сущностях, он останется со ссылкой на сущность OnceApplicatifTerminal, и из-за ваших настроек каскадирования Persist/Merge это приведет к его воскрешению, Просто удалив настройки каскада в TerminalDo->ApplicatifTerminalDo, как будто ссылка не удалена, кэш все равно останется со ссылкой на эту несуществующую сущность.
Удаление осиротевших объектов следует использовать осторожно и только в отношениях, на которые ссылающаяся сущность не ссылается другими сущностями, или необходимо заранее позаботиться об очистке этих ссылок.