Question

J'ai un problème avec une simple cartographie @OneToMany entre un parent et une entité enfant. Tout fonctionne bien, seulement que les dossiers des enfants ne sont pas supprimés quand je les supprimer de la collection.

Le parent:

@Entity
public class Parent {
    @Id
    @Column(name = "ID")
    private Long id;

    @OneToMany(cascade = {CascadeType.ALL}, mappedBy = "parent")
    private Set<Child> childs = new HashSet<Child>();

 ...
}

L'enfant:

@Entity
public class Child {
    @Id
    @Column(name = "ID")
    private Long id;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name="PARENTID", nullable = false)
    private Parent parent;

  ...
}

Si je supprime maintenant et enfant du Childs Set, il ne soit pas supprimé de la base de données. J'ai essayé de réduire à néant la référence child.parent, mais cela ne fonctionne pas non plus.

Les entités sont utilisées dans une application Web, la suppression se produit dans le cadre d'une requête Ajax. Je n'ai pas une liste de Childs lorsque le bouton d'enregistrement supprimé est pressé, donc je ne peux pas les supprimer implicitement.

Était-ce utile?

La solution

Le comportement de JPA est correct (ce qui signifie selon la spécification ): les objets ne sont pas supprimés simplement parce que vous les avez supprimés d'une collection OneToMany. Il existe des extensions spécifiques au fournisseur qui le font, mais JPA native ne sont pas adaptés pour elle.

En partie parce que JPA ne sait pas vraiment si elle devrait supprimer quelque chose retiré de la collection. En termes de modélisation objet, c'est la différence entre composition et « l'agrégation *.

composition , l'entité enfant n'a pas d'existence sans parent. Un exemple classique est entre la maison et la chambre. Supprimer la Chambre et les chambres vont trop.

Agrégation est un looser type d'association et se caractérise par cours et étudiants. Supprimer le cours et l'étudiant existe encore (probablement dans d'autres cours).

Vous devez donc utiliser soit fournisseur spécifique des extensions pour forcer ce comportement (le cas échéant) ou supprimer explicitement l'enfant et le retirer de la collection du parent.

Je suis au courant:

Autres conseils

En plus de la réponse de Cletus, JPA 2.0 , finale depuis Décembre 2010 , introduit un attribut orphanRemoval sur les annotations de @OneToMany. Pour plus de détails, voir cette .

Notez que depuis la spécification est d'avoir une finale implémentation JPA 2 relativement nouveau, pas tout fournisseur JPA 1. Par exemple, le Mise en veille prolongée 3.5.0-Beta-2 version ne supporte pas encore cet attribut.

Vous pouvez essayer ceci:

@OneToOne(orphanRemoval=true) or @OneToMany(orphanRemoval=true).

Comme expliqué, il est impossible de faire ce que je veux avec JPA, donc j'employé l'annotation hibernate.cascade, avec cela, le code correspondant dans la classe parente ressemble maintenant à ceci:

@OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH}, mappedBy = "parent")
@Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE,
            org.hibernate.annotations.CascadeType.DELETE,
            org.hibernate.annotations.CascadeType.MERGE,
            org.hibernate.annotations.CascadeType.PERSIST,
            org.hibernate.annotations.CascadeType.DELETE_ORPHAN})
private Set<Child> childs = new HashSet<Child>();

Je ne pouvais pas utiliser simple « ALL » comme cela aurait supprimé le parent aussi bien.

Ici cascade, dans le contexte de supprimer, signifie que les enfants sont supprimés si vous supprimez le parent. Pas l'association. Si vous utilisez Hibernate comme fournisseur JPA, vous pouvez le faire en utilisant mise en veille prolongée en cascade spécifique.

Vous pouvez essayer ceci:

@OneToOne(cascade = CascadeType.REFRESH) 

ou

@OneToMany(cascade = CascadeType.REFRESH)
@Entity 
class Employee {
     @OneToOne(orphanRemoval=true)
     private Address address;
}

Voir .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top