Оскільки це питання дуже поширене, ця відповідь базується на цій статті, яку я написав у своєму блозі.
CascadeType.REMOVE
CascadeType.REMOVEСтратегія, яку ви можете налаштувати в явному вигляді:
@OneToMany(
mappedBy = "post",
cascade = CascadeType.REMOVE
)
private List<PostComment> comments = new ArrayList<>();
або неявно успадкувати його від CascadeType.ALLстратегії:
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL
)
private List<PostComment> comments = new ArrayList<>();
дозволяє розповсюдити removeоперацію від батьківської сутності до її дочірніх сутностей.
Отже, якщо ми дістаємо батьківську Postсутність разом з її commentsколекцією та видаляємо postсутність:
Post post = entityManager.createQuery("""
select p
from Post p
join fetch p.comments
where p.id = :id
""", Post.class)
.setParameter("id", postId)
.getSingleResult();
entityManager.remove(post);
Hibernate виконає три оператори видалення:
DELETE FROM post_comment
WHERE id = 2
DELETE FROM post_comment
WHERE id = 3
DELETE FROM post
WHERE id = 1
У PostCommentдочірніх об'єктах були видалені з-за CascadeType.REMOVEстратегії, яка діяла , як якщо б ми прибрали дочірні об'єкти , а також.
Стратегія вилучення сиріт
Стратегія вилучення сиріт, яку потрібно встановити через orphanRemovalатрибут:
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();
дозволяє видалити рядок дочірньої таблиці після видалення дочірньої сутності з колекції.
Отже, якщо ми завантажимо Postсутність разом із її commentsколекцією та видалимо першу PostCommentз commentsколекції:
Post post = entityManager.createQuery("""
select p
from Post p
join fetch p.comments c
where p.id = :id
order by p.id, c.id
""", Post.class)
.setParameter("id", postId)
.getSingleResult();
post.remove(post.getComments().get(0));
Hibernate виконує оператор DELETE для відповідного post_commentрядка таблиці:
DELETE FROM post_comment
WHERE id = 2
Докладніше про цю тему також ознайомтесь із цією статтею .