2010-08-02 10 views
5

Ho un'applicazione che utilizza Hibernate per la persistenza dei dati, con Spring in cima (per una buona misura). Fino a poco tempo fa, c'era una classe persistente nell'applicazione, A:È una cattiva pratica usare DiscriminatorFormula per la migrazione dei database di Hibernate?

@Entity 
public class A { 
    @Id 
    @Column(unique = true, nullable = false, updatable = false) 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private long id; 
    public String name; 
} 

allora ho aggiunto una sottoclasse di A, chiamato B:

@Entity 
public class B extends A { 
    public String description; 
} 

Dopo aver aggiunto B, ora potevo non caricare una di . La seguente eccezione è stato gettato:

class org.springframework.orm.hibernate3.HibernateObjectRetrievalFailureException :: Object with id: 1 was not of the specified subclass: A (Discriminator: null); nested exception is org.hibernate.WrongClassException: Object with id: 1 was not of the specified subclass: A (Discriminator: null) 

ho aggiunto la seguente annotazione e la proprietà a B, e sembra aver risolto il problema. È questo il modo giusto per risolvere il problema?

... 
@DiscriminatorFormula("(CASE WHEN dtype IS NULL THEN 'A' ELSE dtype END)") 
public class A { 
    private String dtype = this.getClass().getSimpleName(); 
    ... 

risposta

2

(...) Fino a poco tempo fa, c'era una classe persistente nell'applicazione, A:

Con la seguente rappresentazione del database:

ID NAME 
-- ---- 
1 foo 
2 bar 

I Da allora ha aggiunto una sottoclasse di A, chiamata B (...)

E non è stata specificata l'annotazione Inheritance in modo da utilizzare la strategia di mappatura SINGLE_TABLE. E In questa strategia, tutte le classi in una gerarchia vengono mappate su una singola tabella. La tabella ha una colonna che funge da "colonna discriminatore", ovvero una colonna il cui valore identifica la sottoclasse specifica a cui appartiene l'istanza rappresentata dalla riga.

La tabella divenne poi:

ID NAME DTYPE 
-- ---- ----- 
1 foo NULL 
2 bar NULL 

Dove DTYPE è il nome predefinito di colonna da utilizzare per il discriminatore.

Dopo aver aggiunto B, ora non posso caricare A's. La seguente eccezione è stata lanciata (...)

Infatti, poiché i valori esistenti hanno un valore nullo nella colonna discriminatore, il provider non sa quale sottoclasse istanziare.

Ho aggiunto la seguente annotazione e proprietà a B, e sembra aver risolto il problema. È questo il modo giusto per risolvere il problema?

Questo è un modo ma è invadente (le entità non devono essere a conoscenza della colonna dtype) e di Hibernate. In altre parole, è un hack.

Per me, il modo "giusto" per risolvere questo sarebbe quello di aggiornare la colonna DTYPE di esistere record per impostare il valore a 'A' (con Hibernate, il valore di default il nome dell'entità):

UPDATE A SET DTYPE='A' WHERE DTYPE=NULL 

In questo modo, Hibernate sarebbe in grado di caricarli correttamente.

+0

grazie per la risposta dettagliata. Sfortunatamente non avrò accesso diretto a tutte le installazioni dell'applicazione, quindi mi piacerebbe che lo schema cambiasse in modo trasparente per gli utenti. Ho provato ad aggiungere il DiscriminatorFormula senza definire esplicitamente il campo dtype, ma questo non ha funzionato. Mi è sembrato un trucco quando lo stavo facendo - è per questo che ho chiesto. – Armand

+1

@ Alison, prego. Ti ho dato ciò che è IMO la soluzione "ideale". Se non è adatto nel tuo contesto, se non puoi fornire uno script di migrazione ai tuoi utenti (che eseguirà 'UPDATE' dopo i vari' ALTER') - o ancora meglio uno strumento di migrazione automatica - allora la tua soluzione è accettabile. Almeno funziona. E ora sai che è un po 'un trucco :) –

+0

-) Ho trovato informazioni sulle migrazioni a Hibernate/Spring piuttosto difficili da trovare, sfortunatamente. – Armand

Problemi correlati