Quelle est la signification de CascadeType.ALL pour une association @ManyToOne JPA

210

Je pense que j'ai mal compris le sens de la cascade dans le contexte d'une @ManyToOnerelation.

L'affaire:

public class User {

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

}

public class Address {

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

}

Quelle est la signification du cascade = CascadeType.ALL? Par exemple, si je supprime une certaine adresse de la base de données, comment le fait que j'ai ajouté cascade = CascadeType.ALLaffecte-t-il mes données (le User, je suppose)?

forhas
la source

Réponses:

360

Le sens de CascadeType.ALLest que la persistance propagera (cascade) toutes les EntityManageropérations ( PERSIST, REMOVE, REFRESH, MERGE, DETACH) aux entités liées.

Dans votre cas, cela semble être une mauvaise idée, car la suppression d'un Addressentraînerait la suppression du connexe User. Comme un utilisateur peut avoir plusieurs adresses, les autres adresses deviendraient orphelines. Cependant, le cas inverse (annoter le User) aurait un sens - si une adresse appartient à un seul utilisateur, il est sûr de propager la suppression de toutes les adresses appartenant à un utilisateur si cet utilisateur est supprimé.

BTW: vous souhaiterez peut-être ajouter un mappedBy="addressOwner"attribut à votre Userpour signaler au fournisseur de persistance que la colonne de jointure doit se trouver dans la table ADDRESS.

kostja
la source
55
+1 pour la meilleure et la plus courte explication de mappedBy que j'ai jamais rencontrée.
Ridcully
4
Il pourrait être bon d'avoir CascadeType.ALL du côté @OneToMany.
mvmn
48

Voir ici pour un exemple tiré des documents OpenJPA. CascadeType.ALLsignifie qu'il fera toutes les actions.

Citation:

CascadeType.PERSIST: lors de la persistance d'une entité, conservez également les entités contenues dans ses champs. Nous suggérons une application libérale de cette règle en cascade, car si l'EntityManager trouve un champ qui référence une nouvelle entité lors du vidage et que le champ n'utilise pas CascadeType.PERSIST, c'est une erreur.

CascadeType.REMOVE: lors de la suppression d'une entité, il supprime également les entités contenues dans ce champ.

CascadeType.REFRESH: lors de l'actualisation d'une entité, actualisez également les entités contenues dans ce champ.

CascadeType.MERGE: lors de la fusion de l'état d'entité, fusionnez également les entités contenues dans ce champ.

Sébastien

seba.wagner
la source
4
Nouveau dans JPA, ces informations sont utiles mais qu'en est-il de Détacher ici?
Sarz
1
Dans CascadeType.DETACH, lors du détachement d'une entité, em détache également les entités détenues par l'entité parent.
Dorian Mejer
29

Comme je l'ai expliqué dans cet article et dans mon livre, Persistance Java haute performance , vous ne devriez pas utiliser CascadeType.ALLdessus @ManyToOnecar les transitions d'état d'entité doivent se propager des entités parent aux entités enfant, et non l'inverse.

Le @ManyToOnecôté est toujours l'association enfant car il mappe la colonne de clé étrangère sous-jacente.

Par conséquent, vous devez déplacer le CascadeType.ALLde l' @ManyToOneassociation au @OneToManycôté, ce qui devrait également utiliser l' mappedByattribut car il est un à plusieurs le plus efficace cartographie des relations de table .

Vlad Mihalcea
la source
18

De la spécification EJB3.0 :

L'utilisation de l'élément d'annotation en cascade peut être utilisée pour propager l'effet d'une opération aux entités associées. La fonctionnalité de cascade est généralement utilisée dans les relations parent-enfant.

Si X est une entité gérée, l'opération de suppression entraîne sa suppression. L'opération de suppression est mise en cascade vers les entités référencées par X, si les relations entre X et ces autres entités sont annotées avec la valeur de l'élément d'annotation cascade = REMOVE ou cascade = ALL.

Ainsi, en résumé, les relations d'entité définies avec CascadeType.Allgarantiront que tous les événements de persistance tels que persister, actualiser, fusionner et supprimer qui se produisent sur le parent seront transmis à l'enfant. La définition d'autres CascadeTypeoptions offre au développeur un niveau de contrôle plus granulaire sur la façon dont l'association d'entités gère la persistance.

Par exemple, si j'avais un livre d'objets contenant une liste de pages et que j'ajoute un objet de page dans cette liste. Si l' @OneToManyannotation définissant l'association entre le livre et la page est marquée comme CascadeType.All, la persistance du livre entraînerait la persistance de la page dans la base de données.

Kevin Bowersox
la source
11

Dans JPA 2.0, si vous souhaitez supprimer une adresse si vous l'avez supprimée d'une entité utilisateur, vous pouvez l'ajouter orphanRemoval=true(au lieu de CascadeType.REMOVE) à votre @OneToMany.

Plus d'explications entre orphanRemoval=trueet CascadeType.REMOVEest ici .

Emilien Brigand
la source
4

Si vous souhaitez simplement supprimer l'adresse attribuée à l'utilisateur et ne pas affecter la classe d'entité utilisateur, vous devriez essayer quelque chose comme ça:

@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;
}

De cette façon, vous n'avez pas à vous soucier de l'utilisation de la récupération dans les annotations. Mais n'oubliez pas que lors de la suppression de l'utilisateur, vous supprimerez également l'adresse connectée à l'objet utilisateur.

szachMati
la source