2009-08-11 6 views
2

J'ai un objet Hibernate qui est détaché et transféré vers un client Swing Swing épais utilisant des EJB. L'objet est ensuite modifié d'une manière ou d'une autre et renvoyé au serveur où le serveur met ensuite à jour l'objet modifié dans la base de données. Tout fonctionne bien pour les propriétés qui changent, mais j'ai un problème sur la façon de supprimer un mappage many-to-one.Hibernate - Comment supprimer en cascade des objets détachés

Par exemple, compte tenu de la correspondance suivante:

<hibernate-mapping> 
<class name="com.wg.common.bean.Patient" table="patient"> 
    <id name="id" type="integer"> 
     <column name="id" /> 
     <generator class="sequence"> 
      <param name="sequence">patient_id_seq</param> 
     </generator> 
    </id> 
    <many-to-one name="address" class="com.wg.common.bean.Address" cascade="all"> 
     <column name="address_id" /> 
    </many-to-one> 
    ... 

Dire que j'ai un objet patient est envoyé au client. L'utilisateur a déjà ajouté une adresse. Il ne peut y avoir qu'une seule adresse par patient. Sur le client si l'utilisateur supprime l'adresse, j'appelle setAddress(null) sur l'objet patient avant de retourner au serveur. Quand j'arrive au serveur, il enregistre le champ address_id comme nul, mais laisse l'enregistrement d'adresse dans la base de données. Je comprends pourquoi c'est ce qu'il fait. Je ne casse qu'une extrémité de la relation. De préférence j'utiliserais delete-orphan. Cependant, selon la documentation Hibernate, delete-orphan n'est pas disponible pour les mappages many-to-one. La procédure appropriée consiste à faire appel au serveur (pseudo-code):

Address address = patient.getAddress(); 
session.delete(address); 
patient.setAddress(null); 

Le problème avec ce modèle est que si je veux en tenir à un processus de simplement repassant l'objet patient Je veux sauvé, je n'ai aucun moyen de savoir si elle avait une adresse qui doit être supprimée. Je dois faire quelques solutions de contournement moins qu'élégantes pour résoudre ce problème, comme interroger la base de données pour voir s'il y avait une adresse et l'enlever si elle est null dans l'objet passé, ou créer des méthodes setDeleteAddress(boolean), getDeleteAddress() dans la classe Patient et définir ceux du côté client si l'utilisateur veut supprimer l'adresse. Une autre alternative serait de faire de l'association un-à-plusieurs entre Patient et Adresse. Ensuite, je pourrais utiliser delete-orphan. Cependant, comme c'est vraiment une relation en tête-à-tête, je devrais mettre un getter/setter fou dans la classe Patient comme ça afin de ne pas gaspiller mon code avec des références de collection quand il n'y a pas vraiment de collection:

public Address getAddress() { 
    if(addresses != null && addresses.size() > 0) return addresses.get(0); 
    else return null; 
} 

Existe-t-il une meilleure façon de résoudre ce problème? Comment avez-vous géré la suppression d'une entité sur des objets détachés?

Répondre

0

Je fini par créer simplement un deleteFlag dans la classe Address pour désigner à l'EJB que le Address en question devrait être supprimé de la Patient.

0

L'adresse de mappage comme many-to-one semble être la racine de vos problèmes. L'adresse est le «parent» dans une telle relation, ce qui n'a pas beaucoup de sens. Envisagez de le mapper en tant que composant ou en tête-à-tête à la place. Aucune collection ne devrait être impliquée de toute façon.

+1

Je suis d'accord le plusieurs-à-un semble être la racine du problème. Je hérite de ce système. Le problème que je trouve est qu'une relation un-à-un ne supporte pas non plus la cascade delete-orphelin, seulement one-to-many. Très étrange. Merci de votre aide. – Nemi

+1

La cascade "supprimer-orphelin" n'a de sens que lorsque votre cycle de vie "enfant" est lié (et régi par) le cycle de vie de votre "parent". Les associations many-to-one et one-to-one supposent que les deux extrémités de la relation sont indépendantes. Si vous ne pouvez pas changer la base de données (ce que vous devez faire pour mapper ceci comme un composant qui est vraiment ce que vous devez faire), je vous suggère de changer le mappage en un-un et de supprimer manuellement "adresse" quand tu en as besoin. – ChssPly76

0

Il me semble me rappeler qu'il est en fait possible de mapper une relation un-à-un avec une seule propriété dans certains cas. Je ne peux pas vérifier cela, mais il y a quelques conseils dans le documentation.

Alternativement, une clé étrangère avec une contrainte unique, d'employé à personne, peut être exprimée comme:

<many-to-one name="person" class="Person" column="PERSON_ID" unique="true"/> 

Cette association peut être rendue bidirectionnelle en ajoutant ce qui suit à la personne cartographie:

<one-to-one name="employee" class="Employee" property-ref="person"/> 

Vous pourriez avoir à fid dle autour d'un peu et ajouter cascade="delete" au mappage un-à-un.Je n'ai jamais essayé cela moi-même. La meilleure alternative est la réponse de ChssPly76, si vous avez le contrôle sur le schéma de base de données.

+0

J'ai aussi lu sur le qualificatif unique rendant le plusieurs-à-un vraiment un-à-un. Cependant, je ne peux pas trouver l'avantage de cela dans la documentation. Cela ne me permet pas d'utiliser cascade = "all-delete-orphelin", ce dont j'ai vraiment besoin. – Nemi

Questions connexes