Установка orphanRemoval в true при переносе детей от их родителей к другому родителю
Важное замечание : Если вы читаете этот пост, подумайтеэта почта слишком для углубленных обсуждений.
Это довольно обычная практика / ситуация / требование, когда дети одного из родителей могут быть перемещены к другому родителю. Что будет, еслиorphanRemoval
установлен вtrue
на обратной стороне таких отношений?
Рассмотрим в качестве примера любое простое отношение «один ко многим» следующим образом.
Обратная сторона (отдел):
@OneToMany(mappedBy = "department", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<Employee> employeeList = new ArrayList<Employee>(0);
Собственная сторона (Сотрудник):
@JoinColumn(name = "department_id", referencedColumnName = "department_id")
@ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
private Department department;
При объединении операции / действия, как показано ниже (гдеdepartment
является отдельным объектом, предоставленным клиентом),
Employee employee = entityManager.find(Employee.class, 1L);
Department newDepartment = entityManager.contains(department) ? department : entityManager.merge(department);
if (!newDepartment.equals(employee.getDepartment())) {
employee.getDepartment().getEmployeeList().remove(employee);
// Since orphanRemoval is set to true,
// this should cause a row from the database table to be removed inadvertently
// by issuing an addition DELETE DML statement.
}
employee.setDepartment(newDepartment);
employee.setEmployeeName("xyz");
List<Employee> employeeList = newDepartment.getEmployeeList();
if (!employeeList.contains(employee)) {
employeeList.add(employee);
}
entityManager.merge(employee);
Конечно, добавление и удаление сотрудника может быть лучше выполнено / обработано с использованием методов управления защитными связями (связями) в связанных объектах.
Экземпляр отдела предоставляется клиентом. Это отдельная сущность. Это может быть тот же или другой отдел в зависимости от административного действия, выполняемого данным клиентом. В результате, если экземпляр отдела, предоставленный клиентом, отличается от того, который хранится у текущегоEmployee
затем его следует сначала удалить из списка сотрудников (employeeList
) проводится текущимстарый отдел с обратной стороны, связанный с этимEmployee
перед добавлением его в список сотрудников, занимаемых новымdepartment
в комплект поставки.
Как предположение,Employee
строка должна быть случайно удалена из базы данных при удаленииEmployee
экземпляр из списка сотрудников, на который в данный момент ссылается старый отдел отдела (до того, как эта операция была запущена), т. е. при переносе дочернего элемента из родительского в другой родительский дочерний элемент должен быть удален из исходного родительского элемента до того, как принят другим родителем, и эта дочерняя строка должна быть случайно удалена из базы данных (orphanRemoval = true
).
Однако строка сотрудника в таблице базы данных остается неизменной с обновленными значениями столбца. Нет операторов DML, кромеUPDATE
оператор генерируется.
Могу ли я подумать, что миграция детей от своего родителя к другому родителю таким образом не приведет к непреднамеренному удалению этих детей из таблицы базы данных, как они должныне быть?
В настоящее время используется EclipseLink 2.6.0 с JPA 2.1.
РЕДАКТИРОВАТЬ:
ЕслиEmployee
сущность только удаляется (то есть, не добавляется в список после того, как была удалена - не переносится на другого родителя, а просто удаляется) из списка на обратной стороне, затем соответствующая строка удаляется из базы данных также, как обычно (orphanRemoval = true
) но строка просто обновляется, когдаEmployee
сущность (дочерний элемент) добавляется в список другого родителя после того, как он был удален из списка его родного родителя (миграция сущности).
Поставщик, по-видимому, достаточно умен, чтобы обнаружить миграцию детей от их родителей к другому родителю в качестве обновления.
Поведение может быть идентичным как в Hibernate (4.3.6 final), так и в EclipseLink (2.6.0), но на него нельзя полагаться, если это поведение, специфичное для провайдера (не переносимое). Я не могу найти ничего об этом поведении в спецификации JPA.