215 votes

Quelle est la différence entre la clause JPA orphanRemoval=true et la clause DML ON DELETE CASCADE ?

Je suis un peu confus au sujet de la JPA 2.0 orphanRemoval attribut.

Je pense que je peux voir que c'est nécessaire lorsque j'utilise les outils de génération de BD de mon fournisseur JPA pour créer la DDL de la base de données sous-jacente afin d'avoir une ON DELETE CASCADE sur la relation particulière.

Cependant, si la base de données existe et qu'elle possède déjà un numéro d'identification de la base de données. ON DELETE CASCADE sur la relation, n'est-ce pas suffisant pour cascader la suppression de manière appropriée ? Que fait le orphanRemoval faire en plus ?

Cheers

342voto

axtavt Points 126632

orphanRemoval n'a rien à voir avec ON DELETE CASCADE .

orphanRemoval est entièrement Truc spécifique à l'ORM . Il marque l'entité "enfant" à supprimer lorsqu'elle n'est plus référencée par l'entité "parent", par exemple lorsque vous supprimez l'entité enfant de la collection correspondante de l'entité parent.

ON DELETE CASCADE est un chose spécifique à la base de données il supprime la ligne "enfant" dans la base de données lorsque la ligne "parent" est supprimée.

3 votes

Cela signifie-t-il qu'ils ont l'effet sûr, mais qu'un système différent est responsable de sa réalisation ?

125 votes

Anon, cela n'a pas le même effet. ON DELETE CASCADE indique à la BD de supprimer tous les enregistrements enfants lorsque le parent est supprimé. C'est-à-dire que si je supprime la FACTURE, je supprime ensuite tous les ARTICLES de cette FACTURE. OrphanRemoval indique à l'ORM que si je supprime un objet Item de la collection des Items qui appartiennent à un objet Invoice (opération en mémoire), puis que je "sauvegarde" la Invoice, l'Item supprimé doit être supprimé de la DB sous-jacente.

5 votes

Si vous utilisez une relation unidirectionnelle, l'orphelin sera supprimé automatiquement, même si vous ne définissez pas orphanRemoval=true.

122voto

forhas Points 1383

Un exemple tiré de ici :

Lorsqu'un Employee est supprimé, l'opération de suppression est répercutée en cascade sur l'objet d'entité référencé. Address objet entité. À cet égard, orphanRemoval=true et cascade=CascadeType.REMOVE sont identiques, et si orphanRemoval=true est spécifié, CascadeType.REMOVE est redondant.

La différence entre ces deux paramètres réside dans la réaction à la déconnexion d'une relation. Par exemple, comme lors du paramétrage du champ d'adresse à null ou à un autre Address objet.

  • Si orphanRemoval=true est spécifié le déconnecté Address instance est automatiquement supprimée. Ceci est utile pour nettoyer les objets dépendants (par ex. Address ) qui ne devrait pas exister sans une référence de un objet propriétaire (par exemple Employee ).

  • Si seulement cascade=CascadeType.REMOVE est spécifié, aucune action automatique automatique, car la déconnexion d'un lien ne constitue pas une n'est pas une opération de suppression.

Afin d'éviter les références pendantes résultant de la suppression des orphelins, cette fonctionnalité ne doit être activée que pour les champs qui contiennent des objets dépendants privés non partagés.

J'espère que cela rend les choses plus claires.

0 votes

Après avoir lu votre réponse, j'ai compris la différence exacte entre les deux et mon problème a été résolu. Je suis resté bloqué en supprimant les entités enfants de la base de données, si celles-ci sont déconnectées (supprimées) de la collection définie dans l'entité parent. Pour cela, j'ai posé la question ' stackoverflow.com/questions/15526440/ '. J'ajoute juste mon commentaire pour lier les deux questions.

0 votes

@forhas s'il vous plaît parcourir la question stackoverflow.com/questions/58185249/

49voto

Onur Points 442

Au moment où vous supprimez une entité enfant de la collection, vous supprimez également cette entité enfant de la base de données. orphanRemoval implique également que vous ne pouvez pas changer les parents ; si un département a des employés, une fois que vous supprimez cet employé pour le placer dans un autre département, vous aurez par inadvertance supprimé cet employé de la base de données au moment du flush/commit (quel que soit le premier moment). La morale est de mettre orphanRemoval à 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. Le fait d'activer orphanRemoval ajoute aussi automatiquement REMOVE à la liste des cascades.

3 votes

Tout à fait exact... on parle aussi de relation parent/enfant "privée".

1 votes

Cela signifie que dès que j'appelle department.remove(emp); cet employé sera supprimé de la table emp sans même appeler commit()

33voto

Vlad Mihalcea Points 3628

Transitions d'état des entités

JPA traduit les transitions d'état des entités en instructions SQL, comme INSERT, UPDATE ou DELETE.

JPA entity state transitions

Quand vous persist une entité, vous planifiez l'instruction INSERT pour qu'elle soit exécutée lorsque l'entité EntityManager est vidée, soit automatiquement, soit manuellement.

quand vous remove une entité, vous planifiez l'instruction DELETE, qui sera exécutée lorsque le contexte de persistance sera purgé.

Transitions d'état des entités en cascade

Pour des raisons de commodité, JPA vous permet de propager les transitions d'état d'entité des entités mères aux entités filles.

Donc, si vous avez un parent Post entité qui a un @OneToMany association avec le PostComment entité enfant :

Post and PostComment entities

Le site comments dans la collection Post est mise en correspondance comme suit :

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

CascadeType.ALL

Le site cascade indique au fournisseur JPA de transmettre la transition d'état de l'entité depuis le parent Post entité à tous les PostComment entités contenues dans le comments collection.

Ainsi, si vous supprimez le Post entité :

Post post = entityManager.find(Post.class, 1L);
assertEquals(2, post.getComments().size());

entityManager.remove(post);

Le fournisseur JPA va supprimer le PostComment d'abord, et lorsque toutes les entités enfants sont supprimées, il supprime l'entité Post également :

DELETE FROM post_comment WHERE id = 1
DELETE FROM post_comment WHERE id = 2

DELETE FROM post WHERE id = 1

Suppression des orphelins

Lorsque vous réglez le orphanRemoval à l'attribut true le fournisseur JPA va programmer un remove lorsque l'entité enfant est retiré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'adresse de l'utilisateur de l'application post_comment depuis le PostComment n'est plus référencée dans le comments collection :

DELETE FROM post_comment WHERE id = 1

SUR LA SUPPRESSION EN CASCADE

Le site ON DELETE CASCADE est défini au niveau du 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 avez fait cela, si vous supprimez un post rang :

DELETE FROM post WHERE id = 1

Tous les éléments associés post_comment Les entités sont supprimées automatiquement par le moteur de la base de données. Cependant, cette opération peut s'avérer très dangereuse si vous supprimez une entité Root par erreur.

Conclusion

L'avantage de la JPA cascade et orphanRemoval est que vous pouvez également bénéficier du verrouillage optimiste pour éviter les mises à jour perdues.

Si vous utilisez le mécanisme de mise en cascade de JPA, vous n'avez pas besoin d'utiliser les fonctions de niveau DDL ON DELETE CASCADE Cette opération peut s'avérer très dangereuse si vous supprimez une entité racine qui possède de nombreuses entités filles à plusieurs niveaux.

0 votes

Ainsi, dans la partie de votre réponse concernant la suppression des orphelins : post.getComments().remove(postComment) ; fonctionnera dans un mappage bidirectionnel OneToMany uniquement en raison de la cascade Persist. Sans cascade et sans suppression du côté ManyToOne, comme dans votre exemple, la suppression de la connexion entre 2 entités ne serait pas persistée dans la base de données ?

0 votes

La suppression des orphelins n'est pas affectée par CascadeType . C'est un mécanisme complémentaire. Maintenant, vous confondez suppression et 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.

1 votes

Il y a une chose que je ne comprends pas : comment la suppression des orphelins va-t-elle intervenir dans le mappage bidirectionnel si nous ne supprimons jamais la connexion du côté M ? Je pense que le fait de supprimer PostComment de la liste Post sans mettre PostComment.post à null n'entraînera pas la suppression de la connexion entre ces deux entités dans la base de données. C'est pourquoi je pense que la suppression des orphelins n'aura pas lieu, car dans le monde relationnel, PostComment n'est pas orphelin. Je le testerai quand j'aurai un peu de temps libre.

21voto

Heri Points 1528

Le mappage JPA équivalent pour la DDL ON DELETE CASCADE est cascade=CascadeType.REMOVE . La suppression des orphelins signifie que les entités dépendantes sont supprimées lorsque la relation avec leur entité "mère" est détruite. Par exemple, si un enfant est retiré d'une entité @OneToMany sans le supprimer explicitement dans le gestionnaire d'entités.

1 votes

cascade=CascadeType.REMOVE n'est PAS équivalent à ON DELETE CASCADE . On le supprime dans le code de l'application et il n'affecte pas la DDL, les autres exécutions dans la base de données. Voir stackoverflow.com/a/19696859/548473

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X