2010-06-29 10 views
5

Attualmente sto spostando un'applicazione (funzionante) dall'utilizzo di EclipseLink a Hibernate JPA, principalmente è andata abbastanza bene, ma sto trovando una cosa che non posso spiegare, e posso anche Pensa a qualsiasi buon termine di ricerca!Hibernate JPA - ManyToOne relationship not populated

Fondamentalmente, ho quattro entità, con uno-a-molti formando una catena:

EntityA ha una lista di EntityB di, ognuno dei quali ha una lista di EntityC di, ognuna delle quali ha un elenco di EntityD di

ciascuno di questi ha quindi una relazione molti-a-uno in senso contrario, quindi:

EntityD ha un EntityC, che ha un EntityB, che ha un EntityA.

Che è (fortemente ridotto per chiarezza):

@Entity 
public class EntityA { 
    @OneToMany (cascade = CascadeType.All, mappedBy = "entityA") 
    private List<EntityB> entityBList; 
    ... 
} 

@Entity 
public class EntityB { 
    @OneToMany (cascade = CascadeType.All, mappedBy = "entityB") 
    private List<EntityC> entityCList; 

    @JoinColumn (name = "ENTITY_A", referencedColumnName = "ENTITY_A_ID") 
    @ManyToOne (cascade = CascadeType.PERSIST, optional = false) 
    private EntityA entityA; 
} 

@Entity 
public class EntityC { 
    @OneToMany (cascade = CascadeType.ALL, mappedBy = "entityC") 
    private List<EntityD> entityDList; 

    @JoinColumn (name = "ENTITY_B", referencedColumnName = "ENTITY_B_ID") 
    @ManyToOne (cascade = CascadeType.PERSIST, optional = false) 
    private EntityB entityB; 
} 

@Entity 
public class EntityD { 
    @JoinColumn (name = "ENTITY_C", referencedColumnName = "ENTITY_C_ID") 
    @ManyToOne (cascade = CascadeType.PERSIST, optional = false) 
    private EntityC entityC; 
} 

ottengo un'EntityA dal database (guardando in su per la sua chiave primaria), e quindi ottenere un'istanza EntityA ben popolato, con un PersistentBag per il mio List<EntityB>. Vedo un carico pigro che accade quando denuncio quello List<EntityB> e lo stesso si ripete per ottenere EntityC dall'entitàB.

A questo punto, tutto è come mi aspetto, ho un EntityA, B e C tutti completamente popolati con i valori dal database, ma poi cerco di ottenere il mio EntityD, da EntityC, e scoprire che è null.

Il mio gestore di entità è ancora aperto e attivo a questo punto, e anche se lo guardo nel debugger subito dopo aver ottenuto EntityA, posso camminare attraverso le relazioni, fino a EntityC, e di nuovo vedere l'entitàDList 'come nulla.

L'unica soluzione che ho trovato finora è quello di utilizzare:

EntityManager.refresh(entityC); 

che popola tutti i suoi elementi, tra cui una PersistentBag pigramente-caricato per l'entityDList.

Quindi, la mia ipotesi è che Hibernate stia compilando solo i 2 livelli di profondità (o 3, a seconda di come si conta), e rinunciando dopo, anche se non capisco davvero perché sarebbe. Ha senso per qualcuno?

Esiste una soluzione diversa da .refresh? Qualche tipo di configurazione o valore di annotazione che renderà Hibernate popolare i riferimenti fino in fondo?

+0

Qual è il valore impostato per il parametro di configurazione di ibernazione "max_fetch_depth"? –

risposta

2

Grazie ai suggerimenti di persone qui, che sono probabilmente pertinenti, ma non hanno aiutato il mio caso specifico.

Se stai leggendo questo problema con lo stesso problema, probabilmente vale la pena provare il suggerimento max_fetch_depth, ma per qualche motivo non ha funzionato per me (mi piacerebbe suggerimenti sul perché?).

Allo stesso modo, se il vostro @ OneToMany di sono insiemi, piuttosto che liste, facendo un ansioso per lettura o per una parte di sinistra si uniscono, come suggerito da Albert potrebbe funzionare, ma a quanto pare Sospensione solo ti consente di avere un massimo di 1 List che è avidamente inverosimile, se hai bisogno di più, le tue collezioni dovrebbero essere Set. Non l'ho provato, ma ho il sospetto che potrebbe aver risolto il problema.

A meno che qualcuno non abbia un suggerimento migliore, mi limiterò ad aggiornare le chiamate, che in realtà probabilmente ha più senso per la mia applicazione.

1

Questo è davvero divertente. Un modo per aggirare il problema sarebbe quello di interrogare l'oggetto. Un caricamento a ritroso di sinistra in -> B-> C-> D che è anche più veloce se si percorre comunque fino all'oggetto D. Sarebbe qualcosa di simile.

"from A left join fetch B left join fetch C left join fetch D" 

Hai anche provato a fare il rapporto da C-> D ansioso? Curioso cosa accadrà allora ...

+0

Grazie Albert, ho provato entrambi i suggerimenti, senza risultato :(Rendere la relazione desiderosa non ha avuto alcun effetto, quindi ho provato a rendere tutte le 3 relazioni (A-> B-> C-> D) avide, ma Hibernate si è lamentato con "non può simultaneamente prendi più buste "Aggiungendo i join a sinistra a JPQL si otteneva lo stesso risultato Ho trovato qualcosa altrove suggerendo che ciò è dovuto al fatto che le raccolte che sto cercando con impazienza sono elenchi, e che funzionerebbe se li facessi Set, ma Sono troppo pigro per farlo ora, quindi penso che mi limiterò a una chiamata di aggiornamento! – DaveyDaveDave

1

I documenti di ibernazione dicono che è possibile impostarlo con la proprietà hibernate.max_fetch_depth. Il valore predefinito è 3. È possibile trovarlo nello "Hibernate Reference Documentation" a pagina 47.

+0

Grazie per questo - sai se il file hibernate.properties viene utilizzato anche da Hibernate JPA, non riesco a trovarlo una risposta ovunque nei documenti di Hibernate? Ho provato a cambiarlo a 4 e anche a 0, e sembra non avere alcun effetto ... – DaveyDaveDave

+0

OK, ignora il precedente, sembra essere in uso, perché impostando max_fetch_depth a 0 si è rotto altre parti della mia app :) L'impostazione su un numero elevato però (ho provato 4 e 10), non sembra avere alcun effetto; Immagino perché è solo un massimo e qualcos'altro sta persuadendo Hibernate a fermarsi a 3 livelli ...? – DaveyDaveDave

Problemi correlati