2009-02-14 10 views
10

Je rencontre des problèmes lors de la suppression d'un élément d'une liste. La liste est définie dans une superclasse, mais les annotations Hibernate sont appliquées aux accesseurs de propriété dans une sous-classe. Il y a deux méthodes dans la superclasse qui manipulent la liste. La méthode "add" fonctionne correctement, mais "remove" ne conserve pas les modifications. J'ai vérifié mes paramètres en cascade, et il me semble que les choses sont correctes. Est-ce que je fais quelque chose d'impossible? Si non, est-ce que je fais quelque chose de mal?Mise en veille prolongée: la suppression d'un élément d'une liste ne persiste pas

Voici mes classes:.

@Entity 
abstract class Temporal<T> { 
    @Id 
    @GeneratedValue 
    private Long id; 

    @Version 
    private Integer version = null; 

    @Transient 
    protected List<T> content = new ArrayList<T>(); 

    public void remove(T value) { 
     // business logic ... 
     content.remove(value); 
    } 

    public void add(T value) { 
     // business logic ... 
     content.add(value); 
    } 
} 

@Entity 
@AccessType("property") 
class TemporalAsset extends Temporal<Asset> { 
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "temporal") 
    public List<Asset> getContent() { 
     return super.content; 
    } 

    protected void setContent(List<Asset> list) { 
     super.content = list; 
    } 
} 

J'utilise une instance de la classe TemporalAsset comme suit (notez que je n'utilise que la méthode « rafraîchir » pour démontrer le comportement La liste ne correctement persiste même pas si je vide ou ferme la session et ouvre une nouvelle session):

temporalAsset.add(value1); 
temporalAsset.getContent().size() == 1; // true 
session.update(temporalAsset); 

session.refresh(temporalAsset); 

temporalAsset.getContent().size() == 1; // true 

temporalAsset.remove(value1); 
temporalAsset.getContent().size() == 0; // true 
session.update(temporalAsset); 

session.refresh(temporalAsset); 

temporalAsset.getContent().size() == 0; // false, its 1 

Merci.

Répondre

14

Vous devez spécifier explicitement en cascade comme CascadeType.DELETE_ORPHAN.

Essayez de changer le code à

@OneToMany  
@Cascade(cascade = {CascadeType.ALL, CascadeType.DELETE_ORPHAN}, mappedBy = "temporal") 

partie de mise en veille prolongée docs:

Si la durée de vie de l'objet enfant est limitée par la durée de vie de l'objet parent , faire le parent d'un complet objet cycle de vie en spécifiant CascadeType.ALL et org.hibernate.annotations.CascadeType.DELETE_ORPHAN (s'il vous plaît consulter le guide de référence Hibernate pour la sémantique de orpheline supprimer)

+0

C'était tout! merci beaucoup – codefinger

+0

CascadeType.DELETE_ORPHAN est obsolète. Y a-t-il une alternative? –

+5

utilisez @OneToOne (orphanRemoval = true) ou @OneToMany (orphanRemoval = true) selon http://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/annotations/CascadeType.html – FoxyBOA

0

Essayez de supprimer les appels à Session.refresh(). À partir des documents:

Relisez l'état de l'instance donnée à partir de la base de données sous-jacente. Il est déconseillé d'utiliser ceci pour mettre en œuvre des sessions de longue durée qui couvrent de nombreuses tâches métier. Cette méthode est toutefois utile dans certaines circonstances particulières. Par exemple

  • où un déclencheur de base de données modifie l'état d'objet à insérer ou mettre à jour
  • après l'exécution de SQL directe (par exemple. Une mise à jour de masse) dans la même session
  • après l'insertion d'un Blob ou Clob

http://www.hibernate.org/hib_docs/v3/api/org/hibernate/Session.html#refresh(java.lang.Object)

Si vous appelez flush() avant refresh(), qui pourrait résoudre le problème aussi, depuis flush () garantit que tout SQL en attente sera exécuté sur la base de données. En pratique, je n'ai presque jamais vu personne utiliser refresh() et il ne semble pas que vous en ayez besoin dans votre code.

Ce chapitre de la documentation est intéressant à lire:

http://www.hibernate.org/hib_docs/v3/reference/en/html/objectstate.html

+0

J'ai seulement inclus l'actualisation ici pour montrer le comportement. En pratique, le vidage ne persiste pas les modifications de la liste. Je peux même fermer la session, ouvrir une nouvelle session et la liste a toujours sa valeur. – codefinger

0

Vous avez marqué le champ « contenu » transitoire dans la super classe. Je soupçonne au moins que cela cause des problèmes. Avec le mappage dans la sous-classe, vous avez maintenant deux mappages contradictoires pour le même attribut.

+0

, mais cela ne pose aucun problème – codefinger

Questions connexes