Оскільки це дуже поширене питання, я написав цю статтю , на якій ґрунтується ця відповідь.
Переходи сутності держави
JPA переводить переходи стану сутності в оператори SQL, такі як INSERT, UPDATE або DELETE.
Коли ви persist
є суб'єктом господарювання, ви плануєте оператор INSERT, який буде виконуватися при EntityManager
змиванні, автоматично або вручну.
коли ви remove
є суб'єктом господарювання, ви плануєте оператор DELETE, який буде виконаний, коли контекст персистентності змитий.
Каскадні переходи стану сутності
Для зручності JPA дозволяє розповсюджувати переходи стану суб'єктів господарювання від материнських об'єктів до дочірнього.
Отже, якщо у вас є материнське Post
підприємство, яке має @OneToMany
асоціацію з PostComment
дочірнім об'єктом:
comments
Колекція в Post
сутності, відображається наступним чином :
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<Comment> comments = new ArrayList<>();
CascadeType.ALL
cascade
Атрибут повідомляє постачальник JPA передати об'єкт стан переходу від батьківського Post
об'єкта для всіх PostComment
осіб , які утримуються в comments
колекції.
Отже, якщо ви видалите Post
сутність:
Post post = entityManager.find(Post.class, 1L);
assertEquals(2, post.getComments().size());
entityManager.remove(post);
Постачальник JPA збирається спочатку видалити PostComment
об'єкт, а коли всі дочірні сутності будуть видалені, він також видалить Post
сутність:
DELETE FROM post_comment WHERE id = 1
DELETE FROM post_comment WHERE id = 2
DELETE FROM post WHERE id = 1
Видалення сиріт
Коли ви встановите orphanRemoval
атрибут на true
, постачальник JPA планує запланувати remove
операцію, коли дочірнє об'єднання буде видалено з колекції.
Отже, у нашому випадку
Post post = entityManager.find(Post.class, 1L);
assertEquals(2, post.getComments().size());
PostComment postComment = post.getComments().get(0);
assertEquals(1L, postComment.getId());
post.getComments().remove(postComment);
Постачальник JPA збирається видалити пов'язаний post_comment
запис, оскільки сукупність PostComment
більше не посилається на comments
колекцію:
DELETE FROM post_comment WHERE id = 1
НА ВИДАЛЕННІ КАСКАДИ
Значення ON DELETE CASCADE
визначається на рівні FK:
ALTER TABLE post_comment
ADD CONSTRAINT fk_post_comment_post_id
FOREIGN KEY (post_id) REFERENCES post
ON DELETE CASCADE;
Після цього ви видалите post
рядок:
DELETE FROM post WHERE id = 1
Усі асоційовані post_comment
об'єкти автоматично видаляються двигуном бази даних. Однак це може бути дуже небезпечною операцією, якщо ви видалите кореневу сутність помилково.
Висновок
Перевага JPA cascade
та orphanRemoval
варіантів полягає в тому, що ви також можете скористатися оптимістичним блокуванням, щоб запобігти втраченим оновленням .
Якщо ви використовуєте каскадний механізм JPA, вам не потрібно використовувати рівень DDL ON DELETE CASCADE
, що може бути дуже небезпечною операцією, якщо ви видалите кореневу сутність, яка має багато дочірніх сутностей на кількох рівнях.
Більш детально про цю тему перегляньте цю статтю .