Qual é a diferença entre CascadeType.REMOVE e órfão em JPA?

100

Qual é a diferença entre

@OneToMany(cascade=REMOVE, mappedBy="customer")
public List<Order> getOrders() { ... }

e

@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() { ... }

Este exemplo é do Tutorial Java EE, mas ainda não entendo os detalhes.

rand0m86
fonte
A remoção órfã significa que as entidades dependentes são removidas quando o relacionamento com sua entidade "pai" é destruído.
Rahul Tripathi de
1
Escreveu um caso de teste que pode ilustrar o conceito.
Martin Andersson

Respostas:

152

A partir daqui : -

Remover em cascata

Marcar um campo de referência com CascadeType.REMOVE (ou CascadeType.ALL, que inclui REMOVE) indica que as operações de remoção devem ser colocadas em cascata automaticamente para objetos de entidade que são referenciados por esse campo (vários objetos de entidade podem ser referenciados por um campo de coleção):

@Entity
class Employee {
     :
    @OneToOne(cascade=CascadeType.REMOVE)
    private Address address;
     :
}

Remoção de órfãos

JPA 2 suporta um modo em cascata de remoção adicional e mais agressivo que pode ser especificado usando o elemento órfãoRemoval das anotações @OneToOne e @OneToMany:

@Entity
class Employee {
     :
    @OneToOne(orphanRemoval=true)
    private Address address;
     :
}

DIFERENÇA:-

A diferença entre as duas configurações está na resposta à desconexão de um relacionamento. Por exemplo, ao definir o campo de endereço como nulo ou para outro objeto Endereço.

  • Se órfãoRemoval = true for especificado, a instância de endereço desconectada será removida automaticamente. Isso é útil para limpar objetos dependentes (por exemplo, Endereço) que não deveriam existir sem uma referência de um objeto proprietário (por exemplo, Funcionário).
  • Se apenas cascade = CascadeType.REMOVE for especificado, nenhuma ação automática será executada, pois desconectar um relacionamento não é uma
    operação de remoção .
Rahul Tripathi
fonte
87

Uma maneira fácil de entender a diferença entre CascadeType.REMOVEe orphanRemoval=true.

Para remoção de órfãos: Se você chamar setOrders(null), as Orderentidades relacionadas serão removidas no banco de dados automaticamente.

Para remover cascata: Se você chamar setOrders(null), as Orderentidades relacionadas NÃO serão removidas no banco de dados automaticamente.

estude
fonte
2
remover === excluir
Abdull de
9

Suponha que temos uma entidade filha e uma entidade pai. Um pai pode ter vários filhos.

@Entity
class parent {
  //id and other fields
 @OneToMany (orphanRemoval = "true",cascade = CascadeType.REMOVE)
   Set<Person> myChildern;
}

O órfão é um conceito ORM, ele diz se a criança é órfã. também deve ser removido do banco de dados.

Uma criança fica órfã quando não pode ser acessada por seus pais. Por exemplo, se removermos o conjunto de objetos Person (definindo-o como um conjunto vazio) ou substituí-lo por um novo conjunto, o pai não poderá mais acessar os filhos do conjunto antigo e os filhos ficarão órfãos, portanto os filhos estão condenados a ser removido no banco de dados também.

CascadeType.REMOVE é um conceito de nível de banco de dados e diz se o pai for removido, todos os seus registros relacionados na tabela filho devem ser removidos.

Sr. Q
fonte
2

Praticamente a diferença está em se você está tentando atualizar os dados (PATCH) ou substituir totalmente os dados (PUT)

Digamos que você exclua o customerque usar cascade=REMOVEtambém removerá os pedidos dos clientes que parecem intencionais e úteis.

@OneToMany(cascade=REMOVE, mappedBy="customer")
public List<Order> getOrders() { ... }

Agora, digamos que você atualize um customercom orphanRemoval="true"ele excluirá todos os pedidos anteriores e os substituirá pelo fornecido. ( PUTem termos de REST API)

@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() { ... }

Sem as orphanRemovalvelhas ordens seriam mantidas. ( PATCHem termos de REST API)

garg10may
fonte
1

Como essa pergunta é muito comum, essa resposta é baseada neste artigo que escrevi no meu blog.

CascadeType.REMOVE

A CascadeType.REMOVEestratégia, que você pode configurar explicitamente:

@OneToMany(
    mappedBy = "post",
    cascade = CascadeType.REMOVE
)
private List<PostComment> comments = new ArrayList<>();

ou herde-o implicitamente da CascadeType.ALLestratégia:

@OneToMany(
    mappedBy = "post",
    cascade = CascadeType.ALL
)
private List<PostComment> comments = new ArrayList<>();

permite que você propague a removeoperação da entidade pai para suas entidades filho.

Portanto, se buscarmos a Postentidade pai junto com sua commentscoleção e removermos a postentidade:

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);

O Hibernate irá executar três instruções de exclusão:

DELETE FROM post_comment 
WHERE id = 2

DELETE FROM post_comment 
WHERE id = 3

DELETE FROM post 
WHERE id = 1

As PostCommententidades filhas foram excluídas por causa da CascadeType.REMOVEestratégia, que atuou como se tivéssemos removido as entidades filhas também.

A estratégia de remoção de órfãos

A estratégia de remoção de órfãos, que precisa ser definida por meio do orphanRemovalatributo:

@OneToMany(
    mappedBy = "post",
    cascade = CascadeType.ALL,
    orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();

permite remover a linha da tabela filha ao remover a entidade filha da coleção.

Assim, se carregar a Postentidade junto com sua commentscoleção e remover o primeiro PostCommentda commentscoleção:

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));

O Hibernate irá executar uma instrução DELETE para a post_commentlinha da tabela associada :

DELETE FROM post_comment 
WHERE id = 2

Para obter mais detalhes sobre este tópico, consulte também este artigo .

Vlad Mihalcea
fonte