Je suis un peu confus au sujet de l' orphanRemoval
attribut JPA 2.0 .
Je pense que je peux voir qu'il est nécessaire lorsque j'utilise les outils de génération de base de données de mon fournisseur JPA pour créer la base de données DDL sous-jacente pour avoir une ON DELETE CASCADE
relation particulière.
Cependant, si la base de données existe et qu'elle a déjà une ON DELETE CASCADE
relation sur la relation, n'est-ce pas suffisant pour mettre en cascade la suppression de manière appropriée? Que fait le orphanRemoval
en plus?
À votre santé
la source
Un exemple pris forme ici :
Lorsqu'un
Employee
objet entité est supprimé, l'opération de suppression est mise en cascade sur l'Address
objet entité référencé . À cet égard,orphanRemoval=true
etcascade=CascadeType.REMOVE
sont identiques, et siorphanRemoval=true
est spécifié,CascadeType.REMOVE
est redondant.La différence entre les deux paramètres réside dans la réponse à la déconnexion d'une relation. Par exemple, comme lors de la définition du champ d'adresse sur
null
ou sur un autreAddress
objet.Si
orphanRemoval=true
est spécifié, l'Address
instance déconnectée est automatiquement supprimée. Ceci est utile pour nettoyer les objets dépendants (par exempleAddress
) qui ne devraient pas exister sans une référence d'un objet propriétaire (par exempleEmployee
).Si seulement
cascade=CascadeType.REMOVE
est spécifié, aucune action automatique n'est entreprise car la déconnexion d'une relation n'est pas une opération de suppression.Pour éviter de suspendre les références suite à la suppression des orphelins, cette fonctionnalité ne doit être activée que pour les champs contenant des objets dépendants privés non partagés.
J'espère que cela rend les choses plus claires.
la source
Au moment où vous supprimez une entité enfant de la collection, vous supprimerez également cette entité enfant de la base de données. orphanRemoval implique également que vous ne pouvez pas changer de parent; s'il y a un service qui a des employés, une fois que vous retirez cet employé pour le mettre dans un autre service, vous aurez par inadvertance supprimé cet employé de la base de données lors du vidage / validation (ce qui vient en premier). Le moral est de régler orphanRemoval sur true tant que vous êtes certain que les enfants de ce parent ne migreront pas vers un parent différent tout au long de leur existence. L'activation de orphanRemoval ajoute également automatiquement REMOVE à la liste en cascade.
la source
department.remove(emp);
cet employé sera supprimé de la table emp sans même appelercommit()
Le mappage JPA équivalent pour le DDL
ON DELETE CASCADE
estcascade=CascadeType.REMOVE
. La suppression des orphelins signifie que les entités dépendantes sont supprimées lorsque la relation avec leur entité «parente» est détruite. Par exemple, si un enfant est supprimé d'une@OneToMany
relation sans le supprimer explicitement dans le gestionnaire d'entités.la source
cascade=CascadeType.REMOVE
n'est PAS équivalent àON DELETE CASCADE
. Sur supprimer dans le code de l'application et n'affecte pas à DDL, les autres exécutés dans DB. Voir stackoverflow.com/a/19696859/548473La différence est:
- orphanRemoval = true: l'entité "enfant" est supprimée lorsqu'elle n'est plus référencée (son parent ne peut pas être supprimé).
- CascadeType.REMOVE: l'entité "Enfant" est supprimée uniquement lorsque son "Parent" est supprimé.
la source
Transitions d'état d'entité
JPA traduit les transitions d'état d'entité en instructions SQL, telles que INSERT, UPDATE ou DELETE.
Lorsque vous êtes
persist
une entité, vous planifiez l'exécution de l'instruction INSERT lorsque leEntityManager
est vidé, automatiquement ou manuellement.lorsque vous êtes
remove
une entité, vous planifiez l'instruction DELETE, qui sera exécutée lorsque le contexte de persistance est vidé.Transitions d'état d'entité en cascade
Pour plus de commodité, JPA vous permet de propager les transitions d'état d'entité des entités parentes vers les entités enfant.
Donc, si vous avez une
Post
entité parente qui a une@OneToMany
association avec l'PostComment
entité enfant:La
comments
collection de l'Post
entité est mappée comme suit:@OneToMany( mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true ) private List<Comment> comments = new ArrayList<>();
CascadeType.ALL
L'
cascade
attribut indique au fournisseur JPA de transmettre la transition d'état d'entité de l'Post
entité parente à toutes lesPostComment
entités contenues dans lacomments
collection.Donc, si vous supprimez l'
Post
entité:Post post = entityManager.find(Post.class, 1L); assertEquals(2, post.getComments().size()); entityManager.remove(post);
Le fournisseur JPA supprimera d'abord l'
PostComment
entité, et lorsque toutes les entités enfants seront supprimées, il supprimera également l'Post
entité:DELETE FROM post_comment WHERE id = 1 DELETE FROM post_comment WHERE id = 2 DELETE FROM post WHERE id = 1
Élimination des orphelins
Lorsque vous définissez l'
orphanRemoval
attribut surtrue
, le fournisseur JPA va planifier uneremove
opération lorsque l'entité enfant est supprimée de la collection.Donc, dans notre cas,
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);
Le fournisseur JPA va supprimer l'
post_comment
enregistrement associé car l'PostComment
entité n'est plus référencée dans lacomments
collection:DELETE FROM post_comment WHERE id = 1
SUR SUPPRIMER LA CASCADE
Le
ON DELETE CASCADE
est défini au niveau FK:ALTER TABLE post_comment ADD CONSTRAINT fk_post_comment_post_id FOREIGN KEY (post_id) REFERENCES post ON DELETE CASCADE;
Une fois que vous faites cela, si vous supprimez une
post
ligne:DELETE FROM post WHERE id = 1
Toutes les
post_comment
entités associées sont supprimées automatiquement par le moteur de base de données. Cependant, cela peut être une opération très dangereuse si vous supprimez une entité racine par erreur.Conclusion
L'avantage du JPA
cascade
et desorphanRemoval
options est que vous pouvez également bénéficier d' un verrouillage optimiste pour éviter la perte de mises à jour .Si vous utilisez le mécanisme de cascade JPA, vous n'avez pas besoin d'utiliser le niveau DDL
ON DELETE CASCADE
, ce qui peut être une opération très dangereuse si vous supprimez une entité racine qui a de nombreuses entités enfants à plusieurs niveaux.Pour plus de détails sur ce sujet, consultez cet article .
la source
CascadeType
. C'est un mécanisme complémentaire. Maintenant, vous confondez la suppression avec la persistance. La suppression des orphelins consiste à supprimer les associations non référencées tandis que la persistance consiste à enregistrer de nouvelles entités. Vous devez suivre les liens fournis dans la réponse pour mieux comprendre ces concepts.@GaryK réponse est absolument génial, je l' ai passé une heure à la recherche d'une explication par
orphanRemoval = true
rapportCascadeType.REMOVE
et il m'a aidé à comprendre.En résumé:
orphanRemoval = true
fonctionne de la même manière queCascadeType.REMOVE
SEULEMENT SI nous supprimons object (entityManager.delete(object)
) et nous voulons que les objets enfants soient également supprimés.Dans une situation complètement différente, lorsque nous récupérons des données comme
List<Child> childs = object.getChilds()
puis supprimons un enfant (entityManager.remove(childs.get(0)
) en utilisantorphanRemoval=true
, l'entité correspondant àchilds.get(0)
sera supprimée de la base de données.la source
la suppression des orphelins a le même effet que ON DELETE CASCADE dans le scénario suivant: - Disons que nous avons une simple relation plusieurs à un entre une entité étudiante et une entité guide, où de nombreux étudiants peuvent être mappés vers le même guide et dans la base de données, nous avons un relation de clé étrangère entre la table Student et Guide de sorte que la table Student ait id_guide comme FK.
@Entity @Table(name = "student", catalog = "helloworld") public class Student implements java.io.Serializable { @Id @GeneratedValue(strategy = IDENTITY) @Column(name = "id") private Integer id; @ManyToOne(cascade={CascadeType.PERSIST,CascadeType.REMOVE}) @JoinColumn(name = "id_guide") private Guide guide;
// L'entité parente
@Entity @Table(name = "guide", catalog = "helloworld") public class Guide implements java.io.Serializable { /** * */ private static final long serialVersionUID = 9017118664546491038L; @Id @GeneratedValue(strategy = IDENTITY) @Column(name = "id", unique = true, nullable = false) private Integer id; @Column(name = "name", length = 45) private String name; @Column(name = "salary", length = 45) private String salary; @OneToMany(mappedBy = "guide", orphanRemoval=true) private Set<Student> students = new HashSet<Student>(0);
Dans ce scénario, la relation est telle que l'entité étudiante est le propriétaire de la relation et, en tant que telle, nous devons sauvegarder l'entité étudiante afin de conserver l'ensemble du graphe d'objets, par exemple
Guide guide = new Guide("John", "$1500"); Student s1 = new Student(guide, "Roy","ECE"); Student s2 = new Student(guide, "Nick", "ECE"); em.persist(s1); em.persist(s2);
Ici, nous mappons le même guide avec deux objets étudiants différents et puisque CASCADE.PERSIST est utilisé, le graphique d'objet sera enregistré comme ci-dessous dans la table de base de données (MySql dans mon cas)
Tableau ÉTUDIANT: -
ID Nom Département Id_Guide
1 Roy ECE 1
2 Nick ECE 1
Tableau GUIDE: -
ID NOM Salaire
1 Jean 1500 $
et maintenant si je veux supprimer l'un des étudiants, en utilisant
Student student1 = em.find(Student.class,1); em.remove(student1);
et lorsqu'un dossier d'étudiant est supprimé, l'enregistrement de guide correspondant doit également être supprimé, c'est là que l'attribut CASCADE.REMOVE dans l'entité Student entre en image et ce qu'il fait est; il supprime l'étudiant avec l'identifiant 1 ainsi que l'objet de guide correspondant (identifiant 1). Mais dans cet exemple, il y a un autre objet étudiant qui est mappé au même enregistrement de guide et à moins que nous n'utilisions l' attribut orphanRemoval = true dans l'entité de guide, le code de suppression ci-dessus ne fonctionnera pas.
la source