Qual é o significado do CascadeType.ALL para uma associação @ManyToOne JPA

210

Acho que não entendi o significado de cascata no contexto de um @ManyToOnerelacionamento.

O caso:

public class User {

   @OneToMany(fetch = FetchType.EAGER)
   protected Set<Address> userAddresses;

}

public class Address {

   @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
   protected User addressOwner;

}

Qual é o significado do cascade = CascadeType.ALL? Por exemplo, se eu excluir um determinado endereço do banco de dados, como o fato de eu adicionar cascade = CascadeType.ALLafetou meus dados ( Usereu acho)?

forhas
fonte

Respostas:

360

O significado de CascadeType.ALLé que a persistência propagará (em cascata) todas as EntityManageroperações ( PERSIST, REMOVE, REFRESH, MERGE, DETACH) para as entidades relacionadas.

Parece no seu caso uma péssima idéia, pois remover um Addresslevaria à remoção do relacionado User. Como um usuário pode ter vários endereços, os outros endereços se tornarão órfãos. No entanto, o caso inverso (anotando o User) faria sentido - se um endereço pertencer apenas a um único usuário, é seguro propagar a remoção de todos os endereços pertencentes a um usuário se esse usuário for excluído.

Entre: você pode querer adicionar um mappedBy="addressOwner"atributo ao seu Userpara sinalizar ao provedor de persistência que a coluna de junção deve estar na tabela ADDRESS.

kostja
fonte
55
+1 para a melhor e mais curta explicação de mappedBy que eu já encontrei.
Ridcully
4
Pode ser bom ter o CascadeType.ALL no lado @OneToMany.
Mvmn 31/03/19
48

Veja aqui um exemplo dos documentos do OpenJPA. CascadeType.ALLsignifica que ele fará todas as ações.

Citar:

CascadeType.PERSIST: Ao persistir em uma entidade, também persista as entidades mantidas em seus campos. Sugerimos uma aplicação liberal dessa regra em cascata, porque se o EntityManager encontrar um campo que faça referência a uma nova entidade durante a liberação e o campo não usar CascadeType.PERSIST, será um erro.

CascadeType.REMOVE: Ao excluir uma entidade, ele também exclui as entidades mantidas nesse campo.

CascadeType.REFRESH: Ao atualizar uma entidade, também atualize as entidades mantidas nesse campo.

CascadeType.MERGE: Ao mesclar o estado da entidade, mescle também as entidades mantidas nesse campo.

Sebastian

seba.wagner
fonte
4
Novo no JPA, essas informações são úteis, mas e o Desanexar aqui?
Sarz
1
No CascadeType.DETACH, ao desanexar uma entidade, eles também desanexam as entidades mantidas pela entidade pai.
precisa
29

Como expliquei neste artigo e em meu livro, Persistência Java de alto desempenho , você não deve usá CascadeType.ALL-lo, @ManyToOnepois as transições de estado da entidade devem se propagar das entidades pai para as filho, e não o contrário.

O @ManyToOnelado é sempre a associação filho, pois mapeia a coluna chave estrangeira subjacente.

Portanto, você deve mover o CascadeType.ALLda @ManyToOneassociação para o @OneToManylado, que também deve usar o mappedByatributo, pois é o mapeamento de relacionamento de tabela um para muitos mais eficiente .

Vlad Mihalcea
fonte
18

Na especificação EJB3.0 :

O uso do elemento de anotação em cascata pode ser usado para propagar o efeito de uma operação para entidades associadas. A funcionalidade em cascata é mais comumente usada em relacionamentos pai-filho.

Se X é uma entidade gerenciada, a operação de remoção faz com que ela seja removida. A operação de remoção é conectada em cascata às entidades referenciadas por X, se os relacionamentos de X com essas outras entidades forem anotados com o valor do elemento de anotação cascade = REMOVE ou cascade = ALL.

Portanto, em poucas palavras, os relacionamentos de entidade definidos com CascadeType.Allgarantirão que todos os eventos de persistência, como persistência, atualização, mesclagem e remoção que ocorrem no pai, sejam passados ​​para o filho. Definir outras CascadeTypeopções fornece ao desenvolvedor um nível de controle mais granular sobre como a associação da entidade lida com a persistência.

Por exemplo, se eu tivesse um objeto Livro que continha uma Lista de páginas e eu adicionasse um objeto de página dentro dessa lista. Se a @OneToManyanotação que define a associação entre Livro e Página for marcada como CascadeType.All, persistir o Livro resultaria na persistência da Página no banco de dados.

Kevin Bowersox
fonte
11

No JPA 2.0, se você deseja excluir um endereço, se o removeu de uma entidade Usuário, você pode adicionar orphanRemoval=true(em vez de CascadeType.REMOVE) ao seu @OneToMany.

Mais explicações entre orphanRemoval=truee CascadeType.REMOVEestá aqui .

Emilien Brigand
fonte
4

Se você deseja excluir o endereço atribuído ao usuário e não afetar a classe de entidade Usuário, tente algo como:

@Entity
public class User {
   @OneToMany(mappedBy = "addressOwner", cascade = CascadeType.ALL)
   protected Set<Address> userAddresses = new HashSet<>();
}

@Entity 
public class Addresses {
   @ManyToOne(cascade = CascadeType.REFRESH) @JoinColumn(name = "user_id")
   protected User addressOwner;
}

Dessa forma, você não precisa se preocupar em usar a busca em anotações. Mas lembre-se de que ao excluir o usuário, você também excluirá o endereço conectado ao objeto do usuário.

szachMati
fonte