2012-04-15 5 views
6

Sono in perdita qui, e forse è qualcosa di ovvio perché la mia esperienza Hibernate è più debole rispetto ad altre aree.Hibernate scambia la classe incorporabile per la migrazione dei dati esistenti

Nel codice precedente è presente una classe Hibernate . Una delle sue proprietà è questo:

private OldBar bar = new OldBar(); 

OldBar è una classe @Embeddable che utilizza una singola colonna, foobar:

@Embeddable 
public class OldBar { 

    private String fooBar; 

    @Column(length = 10, nullable = false) 
    private String getFooBar() { 
    return fooBar; 
    } 

    @SuppressWarnings("unused") 
    private void setFooBar(String fooBar) { 
    this.fooBar = fooBar; 
    } 
} 

Il problema originale è che avevo bisogno di fare qualcosa con OldBar.fooBar, ma il il design originale aveva dei limiti e aveva questo campo privato, impedendomi di sottoclassi, quindi ho dovuto creare un'intera altra classe, NewBar, per sostituire l'altra e ottenere l'accesso al campo privato. Ho pensato che, dal momento NewBar è anche Embeddable e ha lo stesso @Column designazione, ho potuto solo scambiare il campo nella classe Foo:

private NewBar bar = new NewBar(); 

ho voluto fare questo perché ho i dati esistenti nella colonna foobar, e Volevo utilizzare in modo trasparente questi dati con NewBar anziché OldBar.

Attraverso i log di traccia ho visto che Foo() è stato creato, con la sua versione predefinita di NewBar(), come ci si aspetterebbe, quando viene chiamato il costruttore. Tuttavia, dal codice temporale chiamate Foo.getBar(), per qualche motivo bar è null! Suppongo che Hibernate lo stia impostando su null per qualche motivo --- ma perché Hibernate non legge i dati dalla colonna foobar e crea un'istanza di NewBar? Perché torna a funzionare quando inserisco OldBar al posto di NewBar? Sicuramente non c'è nulla nel database stesso che dice quale delle classi @Embeddable è mappata alla colonna, vero?

Aggiornamento: Questo diventa estraneo e sconosciuto. A volte lascio il codice durante la notte, e il giorno dopo funziona! O il giorno dopo non funziona! Proprio ora non ha funzionato (ovvero, la proprietà foobar è stata impostata su null anziché sul valore nel database), quindi ho creato la classe ExactCopyOfOldBar e l'ho inserita al posto di OldBar. Ha funzionato bene! Quindi torno a NewBar --- semplicemente annullando le mie modifiche temporanee. Funzionava ancora, quando non aveva mai fatto prima! Esiste una sorta di cache in cui Hibernate serializza i valori e non li ottiene dal database? Questo è molto strano

Aggiornamento: Ora non riesco più a far funzionare lo NewBar. Creo OtherBar, che è praticamente identico a NewBar eccetto che ha un nome diverso, e lo collego e funziona, leggendo correttamente la stringa incorporata. Ritorno a NewBar e ottengo di nuovo null. Cosa sta succedendo?

noti che Foo viene caricato attraverso net.databinder.auth.hib.AuthDataApplication.getUser(String username), che è abbastanza semplice:

return (DataUser) Databinder.getHibernateSession().createCriteria(getUserClass()) 
    .add(Restrictions.eq("username", username)).uniqueResult(); 

ho verificato più volte che il (utente) tabella Foo ha una singola riga con i dati corretti, e la cosa più importante è che il campo foobar ha dati. Perché Hibernate mi restituisce un Foo con un campo nullfoobar? Perché il semplice passaggio da NewBar a OtherBar fa sì che riprenda a funzionare? Perché funziona tutto il giorno e poi smette di funzionare dopo che l'ho lasciato durante la notte?

+0

Suppongo che sia vero, ma non lo hai detto: 'Foo.bar' è contrassegnato come' @ Embedded'? –

+0

@Tim Pote: In realtà, abbastanza stranamente, nel codice legacy originale (funzionante), era _non_ contrassegnato come '@ Embedded'. L'ho provato con e senza '@ Embedded' quando ho cambiato forma' OldBar' in 'NewBar', e non ha fatto la differenza. –

+0

@Tim Pote: ho imparato da Hibernate [documentazione] (http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/) che "... se il tipo di proprietà è annotato come @Embeddable, è mappato come @Embedded, "quindi tecnicamente la parte' @ Embedded' è opzionale. –

risposta

1

Questa potrebbe essere la risposta; Dovrò aspettare diversi giorni per vedere se risolve davvero il problema. Ci sono in realtà due parti.

In primo luogo, per la divulgazione completa, la mia classe NewBar era in realtà una sottoclasse di AbstractBar. Alla fine volevo avere diversi tipi di barre incorporabili, quindi ho posizionatoal livello AbstractBar, non al livello NewBar e inserito il campo privato foobar al livello AbstractBar. La cosa divertente è che questo ha funzionato un po 'di tempo. E come ho detto, a volte tornavo il giorno dopo e Hibernate non caricava il campo foobar. Non capisco perché non ha funzionato tutto il tempo o non ha funzionato mai.

In secondo luogo, quando ho cercato di sbarazzarsi di questa gerarchia in modo da eliminare una fonte del problema, ho conflated AbstractBar e NewBar ma ho dimenticato di portare il @Embeddable fino AbstractBar-NewBar, in modo da Hibernate non ha visto che era una classe incorporabile e non sapeva come caricare una stringa in un campo NewBar senza una designazione @Embeddable. Questo è il motivo per cui OtherBar (con annotazione @Embeddable) funzionava, ma non NewBar (senza annotazione @Embeddable). Questo capisco molto. Perché Hibernate non mi ha avvertito che non riusciva a capire come caricare un campo, non lo so.

Quindi, per riepilogare, Hibernate non caricherà un campo integrabile se hai lasciato l'annotazione @Embeddable fuori dalla classe. Per quanto riguarda il problema originale, posso solo supporre che @Embeddable sia instabile quando si tenta di utilizzarlo su una gerarchia di classi e che è meglio mantenere tutti i campi incorporabili a un livello nella classe incorporabile. Spero che questo sia il problema. Vedremo se continuerà a funzionare domani.

Problemi correlati