Important Note: If you are reading this post, then review this post for in-depth discussions.
This is a common practice / situation / requirement where the children of a parent can be transferred to another parent. What happens if orphanRemoval set to true on the back of such a relationship?
As an example, consider any simple one-to-many relationship as follows.
Reverse side (department):
@OneToMany(mappedBy = "department", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) private List<Employee> employeeList = new ArrayList<Employee>(0);
Own side (Employee):
@JoinColumn(name = "department_id", referencedColumnName = "department_id") @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH}) private Department department;
When combining an operation / action similar to the following (where department is a separate entity provided by the client),
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);
Of course, adding and removing an employee can be better done / processed using security management methods in related objects.
A department instance is provided by the customer. This is a separate facility. This may be the same or a different department depending on the administrative action performed by the client. As a result, if the department instance provided by the client is different from the instance stored in the current Employee , you must first remove it from the list of employees ( employeeList ) held by the current old on the back of this Employee before adding it to the list of employees, stored in the new department .
As you can imagine, the Employee row should be accidentally deleted from the database when deleting the Employee instance from the list of employees currently referenced by the department of the employee department - the old department (before this operation was started) i.e. when transferring a child from the parent to another parent, the child must be deleted from its parent before it is accepted by the other parent, and this child row must be accidentally deleted from the database ( orphanRemoval = true ).
However, the employee row in the database table remains unchanged with updated column values. No DML statements are created except for the UPDATE .
Can I consider the possibility of transferring children from my parent to another parent method in such a way that it does not accidentally delete these children from the database table, since they should not be?
Currently using EclipseLink 2.6.0 with JPA 2.1.
EDIT:
If the Employee object is deleted (thus, it is not added to the list after its removal - it is not transferred to the other parent, but simply deleted) from the list on the back, then its corresponding row is deleted from the database as usual ( orphanRemoval = true ) , but the line is simply updated when the Employee object (child) is added to the list of another parent after it is removed from the list of its parent (migration of the object),
The provider seems smart enough to detect the migration of children from its parent to another parent as an update.
The behavior can be seen the same on both Hibernate (4.3.6 final) and EclipseLink (2.6.0), but you cannot rely on it if it is the behavior of a specific provider (not portable). I cannot find anything like this in the JPA specification.