2010-07-21 2 views
12
@Entity 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
@Table(name = "company_policies") 
@DiscriminatorColumn(name = "rule_name") 
public abstract class AbstractPolicyRule implements Serializable { 

    @Transient 
    private static final long serialVersionUID = 1L; 

    @Id 
    @GeneratedValue 
    private Long id; 
    private String value; 

    ... 
} 

_orphelins restent dans la base de données même avec orphanRemoval = true sur un à-plusieurs (JPA/Hibernate)

@Entity 
public class Category implements Serializable { 

    @Transient 
    private static final long serialVersionUID = 1L; 

    @Id 
    @GeneratedValue 
    private Long id; 
    @Column(name = "category_name") 
    private String name; 

    @OneToMany(fetch = FetchType.EAGER, cascade = { CascadeType.ALL }, orphanRemoval = true) 
    @JoinColumn(name = "category_policy_id", referencedColumnName = "id") 
    private Set<AbstractPolicyRule> activePolicyRules; 

    ... 
} 

Lorsque cet ensemble est mis à jour les activePolicyRules existants ont leur category_policy_id à null dans la base de données et les nouveaux sont insérés. J'aimerais que les originaux soient supprimés.

Je pensais que l'ajout de la fonction orphelins = true le ferait mais ce n'est pas le cas. D'autres questions que j'ai vues à ce sujet semblent avoir des relations bidirectionnelles et le fait de mettre le parent à zéro le résout, mais ce n'est pas une relation bidirectionnelle.

Des suggestions?

En utilisant Hibernate 3.5.3

Edit: Cela se produit uniquement lorsqu'un AbstractPolicyRule existant existe dans la base de données, je le supprimer de la liste et puis enregistrez la catégorie à nouveau. C'est la clé étrangère, category_policy_id, est défini sur null au lieu d'être supprimé.

[DEBUG] Collection found: [domain.category.Category.activePolicyRules#1], was: 
[<unreferenced>] (initialized) 
[DEBUG] Flushed: 0 insertions, 2 updates, 0 deletions to 2 objects 
[DEBUG] Flushed: 1 (re)creations, 0 updates, 1 removals to 1 collections 
... 
[DEBUG] Deleting collection: [domain.category.Category2.activePolicyRules#1] 
[DEBUG] about to open PreparedStatement (open PreparedStatements: 0, globally: 0) 
[DEBUG] update company_policies set category_policy_id=null where category_policy_id=? 
[DEBUG] done deleting collection 

a également essayé une table de jointure depuis la documentation Hibernate décourage la façon précédente:

@Entity 
public class Category implements Serializable { 

    @Transient 
    private static final long serialVersionUID = 1L; 

    @Id 
    @GeneratedValue 
    private Long id; 
    @Column(name = "category_name") 
    private String name; 

    @OneToMany(fetch = FetchType.EAGER, cascade = { CascadeType.ALL }, orphanRemoval = true) 
    @JoinTable(name = "policy_rule_mapping", 
    joinColumns = @JoinColumn(name = "category_id"), 
    inverseJoinColumns = @JoinColumn(name = "rule_id")) 
    private Set<AbstractPolicyRule> activePolicyRules; 

    ... 
} 

Cela a le même problème. La ligne de la table de mappage est supprimée, mais AbstractPolicyRule contient toujours l'élément supprimé.

+0

Le scénario que j'ai testé était en fait très proche de votre édition. J'ai changé mon test pour supprimer l'élément existant de la collection sans en ajouter un autre et il est toujours supprimé. Notez que je n'utilise aucun héritage (je pense que vous pourriez l'être). –

Répondre

9

J'utilise orphanRemoval=true avec une association Un-à-Un unidirectionnelle sans aucun problème.

Et en fait, j'ai testé votre code et le scénario suivant (AbstractPolicyRule mise en œuvre correctement equals/hashCode):

Category category = new Category(); 
AbstractPolicyRule policyRule1 = new AbstractPolicyRule("foo"); 

category.addToActivePolicyRules(policyRule1); 
em.persist(category); 
em.flush(); 

assertNotNull(category.getId()); 
assertNotNull(category.getActivePolicyRules()); 
assertEquals(1, category.getActivePolicyRules().size()); 

category.removeFromActivePolicyRules(policyRule1); 
category.addToActivePolicyRules(new AbstractPolicyRule("bar")); 
// category = em.merge(category); // works with or without 
em.flush(); 
assertEquals(1, category.getActivePolicyRules().size()); 

fonctionne exactement comme prévu. Sous les traces générées:

 
22:54:30.817 [main] DEBUG org.hibernate.SQL - insert into Category (id, category_name) values (null, ?) 
Hibernate: insert into Category (id, category_name) values (null, ?) 
22:54:30.824 [main] TRACE org.hibernate.type.StringType - binding null to parameter: 1 
22:54:30.844 [main] DEBUG o.h.id.IdentifierGeneratorHelper - Natively generated identity: 1 
... 
22:54:30.872 [main] DEBUG org.hibernate.SQL - insert into AbstractPolicyRule (id, name) values (null, ?) 
Hibernate: insert into AbstractPolicyRule (id, name) values (null, ?) 
22:54:30.873 [main] TRACE org.hibernate.type.StringType - binding 'foo' to parameter: 1 
22:54:30.874 [main] DEBUG o.h.id.IdentifierGeneratorHelper - Natively generated identity: 1 
... 
22:54:30.924 [main] DEBUG org.hibernate.SQL - update AbstractPolicyRule set category_policy_id=? where id=? 
Hibernate: update AbstractPolicyRule set category_policy_id=? where id=? 
22:54:30.927 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 1 
22:54:30.928 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 2 
22:54:30.929 [main] DEBUG o.h.p.c.AbstractCollectionPersister - done inserting collection: 1 rows inserted 
22:54:30.929 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - Executing batch size: 1 
... 
22:54:30.945 [main] DEBUG org.hibernate.SQL - insert into AbstractPolicyRule (id, name) values (null, ?) 
Hibernate: insert into AbstractPolicyRule (id, name) values (null, ?) 
22:54:30.948 [main] TRACE org.hibernate.type.StringType - binding 'bar' to parameter: 1 
22:54:30.948 [main] DEBUG o.h.id.IdentifierGeneratorHelper - Natively generated identity: 2 
... 
22:54:30.990 [main] DEBUG org.hibernate.SQL - update AbstractPolicyRule set category_policy_id=null where category_policy_id=? and id=? 
Hibernate: update AbstractPolicyRule set category_policy_id=null where category_policy_id=? and id=? 
22:54:30.991 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 1 
22:54:30.992 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 2 
22:54:30.993 [main] DEBUG o.h.p.c.AbstractCollectionPersister - done deleting collection rows: 1 deleted 
22:54:30.993 [main] DEBUG o.h.p.c.AbstractCollectionPersister - Inserting rows of collection: [com.stackoverflow.q3304092.Category.activePolicyRules#1] 
22:54:30.994 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - Executing batch size: 1 
... 
22:54:30.996 [main] DEBUG org.hibernate.SQL - update AbstractPolicyRule set category_policy_id=? where id=? 
Hibernate: update AbstractPolicyRule set category_policy_id=? where id=? 
22:54:30.997 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 1 
22:54:30.998 [main] TRACE org.hibernate.type.LongType - binding '2' to parameter: 2 
22:54:31.002 [main] DEBUG o.h.p.c.AbstractCollectionPersister - done inserting rows: 1 inserted 
... 
22:54:31.015 [main] DEBUG org.hibernate.SQL - delete from AbstractPolicyRule where id=? 
Hibernate: delete from AbstractPolicyRule where id=? 
22:54:31.017 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 1 

La première règle de stratégie est supprimée.

Si ce n'est pas représentatif de ce que vous faites, vous devriez peut-être fournir plus de code.

Mise à jour: Répondre à un commentaire de l'OP ...

Wow, je viens de changer l'appel saveOrUpdate fusionner et maintenant il est l'élimination appropriée. Vous avez un aperçu pourquoi c'est?

Juste une supposition: car orphanRemoval est une chose JPA, je me demande si saveOrUpdate traitera de façon appropriée avec elle (en fait, je pensais que vous utilisiez l'API EntityManager puisque vous avez mentionné JPA).

+0

Merci pour la réponse. J'ai mis à jour mon post avec plus d'informations qui, je l'espère, a du sens. – Josh

+0

Peut-être que je ne comprends pas ce que signifie "définir correctement le code d'égalité/de hachage". À l'heure actuelle, le code égal/hash utilise les identifiants uniques de la table (mais pas l'identifiant). – Josh

+0

@Josh C'est une bonne implémentation (et j'ai utilisé une telle implémentation ci-dessus en essayant de reproduire le problème). –

3

Assurez-vous d'abord que vos classes implémentent les méthodes hashCode() et equals(), afin qu'hibernate sache que ces éléments sont supprimés de l'ensemble.

Ensuite, essayez de définir l'annotation hibernate @Cascade, en spécifiant le type de cascade delete-orphelin et observez si la même chose se produit. Si cela fonctionne comme vous le souhaitez, signalez un bogue dans Hibernate et utilisez temporairement l'annotation propriétaire. Sinon - mettre à jour la question avec les détails

+0

Merci pour la réponse. J'ai mis à jour mon message avec plus d'infos. – Josh

Questions connexes