Search code examples
hibernatejpaeclipselinkcascadejpa-2.1

Cascade types in JPA


Given two entities Department and Employee forming a one-to-many relationship from Department to Employee.

Since the relationship is quite intuitive, I am leaving out the entity classes.

In Department :

@OneToMany(mappedBy = "department", fetch = FetchType.LAZY)
private List<Employee> employeeList = new ArrayList<Employee>(0);

In Employee :

@ManyToOne(fetch = FetchType.LAZY)
private Department department;

Please notice that I have nowhere mentioned cascade = {CascadeType.MERGE} though the following relationships are merged on both the sides (owning and inverse sides).

Employee employee = entityManager.find(Employee.class, 18L);
employee.setEmployeeName("zz");

Department department = employee.getDepartment();
employee.setDepartment(department);

department.setDepartmentName("e");
department.setLocation("e");

entityManager.merge(employee);

While merging Employee, Department is also merged.

Inversely, in this following case,

Department department = entityManager.find(Department.class, 1L);
List<Employee> employeeList = department.getEmployeeList();

for(Employee e:employeeList) {
    if(e.getEmployeeId().equals(27L)) {
        e.setEmployeeName("xxx");
    }
}

// No further EntityManager operation(s) here.

New values set to an Employee instance are directly merged into the associated underlying database.

From OpenJPA :

CascadeType.MERGE: When merging entity state, also merge the entities held in this field.

From EclipseLink Wiki :

MERGE – If the owning entity is merged, the merge is cascaded to the target of the association.

From JPA Wiki Book :

MERGE - Cascaded the EntityManager.merge() operation. If merge() is called on the parent, then the child will also be merged. This should normally be used for dependent relationships. Note that this only affects the cascading of the merge, the relationship reference itself will always be merged. This can be a major issue if you use transient variables to limit serialization, you may need to manually merge, or reset transient relationships in this case. Some JPA providers provide additional merge operations.

Regarding the test cases above, I do not precisely understand when exactly cascade = {CascadeType.MERGE} is needed or useful. What is the use of cascade = {CascadeType.MERGE} in this case?

How do those test cases merge Department and Employee respectively without using cascade = {CascadeType.MERGE}?

I am currently on EclipseLink 2.6.0.


Solution

  • What you're missing is a fundamental feature of JPA: every change made to a managed entity is automatically saved to the database. No need to call merge() or anything else. You open a transaction, get entities, and modify them, then commit the transaction, and that's all you need to modify the database.

    merge() is used to copy changes from a detached entity to its managed counterpart.