Ответ
CascadeType.REMOVE — это параметр каскадирования операций в JPA, который указывает, что при удалении родительской сущности должны быть автоматически удалены все связанные дочерние сущности.
Базовый пример:
@Entity
public class Department {
@Id @GeneratedValue
private Long id;
@OneToMany(mappedBy = "department", cascade = CascadeType.REMOVE)
private List<Employee> employees; // При удалении Department удалятся все Employee
}
@Entity
public class Employee {
@Id @GeneratedValue
private Long id;
@ManyToOne
private Department department;
}
Что происходит при вызове:
Department dept = entityManager.find(Department.class, 1L);
entityManager.remove(dept); // Автоматически удалит всех связанных employees
// Эквивалентно:
// for (Employee emp : dept.getEmployees()) {
// entityManager.remove(emp);
// }
// entityManager.remove(dept);
Отличие от orphanRemoval = true:
// CascadeType.REMOVE vs orphanRemoval
@Entity
public class Parent {
@OneToMany(mappedBy = "parent",
cascade = CascadeType.REMOVE) // Удаление только при удалении Parent
private List<Child> children;
}
@Entity
public class Parent2 {
@OneToMany(mappedBy = "parent",
orphanRemoval = true) // Удаление Child также при отсоединении от Parent
private List<Child> children;
}
// orphanRemoval = true более агрессивен:
Parent2 parent = em.find(Parent2.class, 1L);
parent.getChildren().remove(0); // Child сразу удаляется из БД!
Каскадирование на нескольких уровнях:
@Entity
public class Order {
@Id @GeneratedValue
private Long id;
@OneToMany(mappedBy = "order", cascade = CascadeType.REMOVE)
private List<OrderItem> items;
}
@Entity
public class OrderItem {
@Id @GeneratedValue
private Long id;
@OneToMany(cascade = CascadeType.REMOVE) // Каскад на второй уровень
private List<ItemDetail> details;
}
// Удаление Order → удаление всех OrderItem → удаление всех ItemDetail
Ограничения и особенности:
- Работает только с отношениями, где сущность — владелец связи
- Не работает с @ManyToMany — нужно использовать промежуточную сущность
- Может нарушать foreign key constraints, если не настроены каскады на уровне БД
Лучшие практики:
// 1. Используйте осторожно — неожиданные каскадные удаления
@OneToMany(mappedBy = "department",
cascade = {CascadeType.PERSIST, CascadeType.MERGE}) // Без REMOVE!
// 2. Явное удаление через репозиторий безопаснее
@Service
public class DepartmentService {
@Transactional
public void deleteDepartment(Long deptId) {
// Явный контроль над удалением связанных данных
departmentRepo.deleteEmployeesByDepartmentId(deptId);
departmentRepo.deleteById(deptId);
}
}
// 3. Каскад на уровне БД (более эффективно)
ALTER TABLE employee
ADD CONSTRAINT fk_department
FOREIGN KEY (department_id)
REFERENCES department(id)
ON DELETE CASCADE;
Полный список CascadeType:
- PERSIST — каскадное сохранение
- MERGE — каскадное обновление
- REMOVE — каскадное удаление
- REFRESH — каскадное обновление из БД
- DETACH — каскадное отсоединение
- ALL — все вышеперечисленные