Como essa é uma pergunta muito comum, escrevi este artigo , no qual essa resposta se baseia.
Transições de estado da entidade
O JPA converte transições de estado da entidade para instruções SQL, como INSERT, UPDATE ou DELETE.
Quando você é persist
uma entidade, está agendando a instrução INSERT para ser executada quando EntityManager
for liberada, automática ou manualmente.
quando você é remove
uma entidade, está agendando a instrução DELETE, que será executada quando o contexto de persistência for liberado.
Transições de estado da entidade em cascata
Por conveniência, o JPA permite propagar transições de estado de entidade de entidades pai para filho filho.
Portanto, se você tem uma Post
entidade pai que tem uma @OneToMany
associação com a PostComment
entidade filho:
A comments
coleção na Post
entidade é mapeada da seguinte maneira:
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<Comment> comments = new ArrayList<>();
CascadeType.ALL
O cascade
atributo informa ao provedor JPA para passar a transição do estado da entidade da entidade pai Post
para todas as PostComment
entidades contidas na comments
coleção.
Portanto, se você remover a Post
entidade:
Post post = entityManager.find(Post.class, 1L);
assertEquals(2, post.getComments().size());
entityManager.remove(post);
O provedor JPA removerá a PostComment
entidade primeiro e, quando todas as entidades filhas forem excluídas, a Post
entidade também será excluída :
DELETE FROM post_comment WHERE id = 1
DELETE FROM post_comment WHERE id = 2
DELETE FROM post WHERE id = 1
Remoção de órfãos
Quando você define o orphanRemoval
atributo como true
, o provedor JPA agendará uma remove
operação quando a entidade filha for removida da coleção.
Então, no nosso caso,
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);
O provedor JPA removerá o post_comment
registro associado, pois a PostComment
entidade não é mais referenciada na comments
coleção:
DELETE FROM post_comment WHERE id = 1
EM EXCLUIR CASCADE
O ON DELETE CASCADE
é definido no nível FK:
ALTER TABLE post_comment
ADD CONSTRAINT fk_post_comment_post_id
FOREIGN KEY (post_id) REFERENCES post
ON DELETE CASCADE;
Depois de fazer isso, se você excluir uma post
linha:
DELETE FROM post WHERE id = 1
Todas as post_comment
entidades associadas são removidas automaticamente pelo mecanismo de banco de dados. No entanto, isso pode ser uma operação muito perigosa se você excluir uma entidade raiz por engano.
Conclusão
A vantagem do JPA cascade
e das orphanRemoval
opções é que você também pode se beneficiar do bloqueio otimista para evitar atualizações perdidas .
Se você usar o mecanismo de cascata JPA, não precisará usar o nível DDL ON DELETE CASCADE
, o que pode ser uma operação muito perigosa se você remover uma entidade raiz que possui muitas entidades filhas em vários níveis.
Para mais detalhes sobre este tópico, consulte este artigo .