2010-07-21 12 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; 

    ... 
} 

_orfani rimangono nel database anche con orphanRemoval = true su uno-a-molti (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; 

    ... 
} 

Quando questo Set viene aggiornato i activePolicyRules esistenti hanno la loro category_policy_id impostato su null in il database e quelli nuovi sono inseriti. Mi piacerebbe che gli originali venissero cancellati.

Ho pensato di aggiungere orphanRemoval = true, ma non lo è. Altre domande che ho visto su questo sembrano avere relazioni bidirezionali e l'impostazione del genitore su null lo risolve, ma questa non è una relazione bidirezionale.

Qualche suggerimento?

usando Hibernate 3.5.3

Edit: Questo accade solo quando esiste un AbstractPolicyRule esistente nel database, rimuovo dalla lista e quindi salvare di nuovo Categoria. La sua chiave esterna, category_policy_id, è impostata su null invece di essere cancellata.

[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 

provato anche un tavolo da unirsi in quanto la documentazione Hibernate scoraggia il modo precedente:

@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; 

    ... 
} 

Questo ha lo stesso problema. La riga nella tabella di mapping viene eliminata, ma AbstractPolicyRule contiene ancora l'elemento rimosso.

+0

Lo scenario che ho provato era in realtà molto vicino alla tua modifica. Ho modificato il mio test per rimuovere l'elemento esistente dalla raccolta senza aggiungerne un altro e viene comunque eliminato. Nota che non sto usando alcuna eredità (penso che tu possa essere). –

risposta

9

Sto usando orphanRemoval=true con un'associazione One-To-Many unidirezionale senza alcun problema.

E in realtà, ho provato il codice e il seguente scenario (AbstractPolicyRule attuazione equals/hashCode correttamente):

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()); 

funziona proprio come previsto. Sotto le tracce generate:

 
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 prima regola politica viene eliminata.

Se questo non è rappresentativo di quello che stai facendo, dovresti forse fornire più codice.

Aggiornamento: Rispondere a un commento da PO ...

Wow ho appena cambiato la chiamata saveOrUpdate di fondere e ora è la rimozione in modo appropriato. Hai qualche idea del perché?

Solo una supposizione: dal orphanRemoval è una cosa JPA, mi chiedo se saveOrUpdate si occuperà in modo appropriato con esso (in realtà, ho pensato che si stava utilizzando l'API EntityManager poiché lei ha citato JPA).

+0

Grazie per la risposta. Ho aggiornato il mio post con più informazioni che si spera abbiano senso. – Josh

+0

Forse non sto capendo cosa significhi "impostare equamente/codice hash". In questo momento il codice equals/hash sta usando gli identificatori univoci per la tabella (ma non l'id). – Josh

+0

@Josh Questa è una buona implementazione (e ho usato tale implementazione sopra quando provo a riprodurre il problema). –

3

Prima assicurati che le tue classi implementino i metodi hashCode() e equals(), in modo che sappia che esattamente questi elementi sono stati rimossi dal set.

Quindi provare a definire l'hibernate @Cascade annotazione, specificando il tipo delete-orphan cascade lì e osservatore se lo stesso accade. Se funziona nel modo desiderato, segnala un errore in ibernazione e utilizza temporaneamente l'annotazione proprietaria. Altrimenti, aggiorna la domanda con i dettagli

+0

Grazie per la risposta. Ho aggiornato il mio post con maggiori informazioni. – Josh

Problemi correlati