2011-09-22 17 views
7

la mia domanda riguarda JPA 2.0 con Hibernate, @OneToOne e il caricamento lazy.JPA 2.0/Hibernate: Perché il caricamento di LAZY con "@OneToOne" funziona senza problemi?

Prima la mia configurazione:

  • Primavera 3.0.5.RELEASE
  • SprnigData JPA 1.0.1.RELEASE
  • Hibernate 3.5.2-finali
  • DBMS: PostgreSQL 9.0

Recentemente mi sono imbattuto nel fatto che una relazione @OneToOne non può essere recuperata in modo lazy (FetchType.LAZY), almeno non senza byte instrumentatio n, compilare la tessitura del tempo o simili. Molti siti là fuori dicono che questo, ad esempio:

Il fatto è che, con la mia messa a punto, un lazy loading di un'entità @OneToOne sembra funzionare "out of the box", e mi piacerebbe davvero capire perché. Si prega, dare un'occhiata al mio test di unità:

@Test 
@Transactional 
public void testAvatarImageLazyFetching() 
{ 
    User user = new User(); 
    user.setAvatarImage(new AvatarImage()); 

    User = userRepository.save(user); 

    entityManager.flush(); 
    entityManager.clear(); 

    User loadedUser = userRepository.findOne(user.getId()); 
    assertNotNull(loadedUser); 

    PersistenceUtil persistenceUtil = Persistence.getPersistenceUtil(); 

    assertTrue(persistenceUtil.isLoaded(loadedUser)); 
    assertFalse(persistenceUtil.isLoaded(loadedUser, "avatarImage")); 
} 

Questo caso prova è riuscita, e in Hibernates output della registrazione SQL, posso vedere chiaramente, che il "avatarImage" non sarà recuperato, solo il "utente" (solo un singolo SELECT, nessun JOIN, non ha accesso al "AvatarImage" tavolo etc.)

il @OneToOne proficua relazione unidirezionale nella classe utente si presenta così:

@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) 
private AvatarImage avatarImage; 

Quindi, tutto molto semplice - e sembra funzionare.

Per ripetere la mia domanda: perché funziona, perché è possibile recuperare pigramente l '"AvatarImage", sebbene venga fatto riferimento a un'associazione @OneToOne?

Apprezzo molto tutto l'aiuto che si può offrire

Grazie mille!

risposta

8

Il problema con il caricamento lento della relazione OneToOne è solo nella parte opposta di esso (quello contrassegnato con l'attributo mappedBy). Funziona bene sul lato proprietario della relazione. T la differenza tra quelli è chiara a livello di database. Nel tuo caso la domanda è se la tabella del database utente contiene un id di AvatarImage come una delle colonne o viceversa. Se la tabella utente ha una colonna con un ID di AvatarImage, il caricamento lento funzionerà come hai detto "out-of-box" ma non funzionerà al contrario.

3

Il recupero pigro funziona fuori dalla scatola per le relazioni annotate @OneToOne, con il provider JPA Hibernate, quando viene eseguita una qualche forma di strumentazione bytecode. Nel tuo caso, potremmo escludere la strumentazione del tempo di costruzione (deducendo dal tuo commento che funziona immediatamente). Questo ti lascia la possibilità di tessere a runtime, il che è del tutto possibile in Hibernate & Spring. Nelle versioni recenti di Hibernate, Javassist viene utilizzato come framework di strumentazione bytecode di runtime per Hibernate, in contrasto con l'altra alternativa di CGLIB (which has been deprecated since Hibernate 3.5.5).

La domanda se Javassist è abilitato in primavera è una risposta abbastanza semplice. Hibernate EntityManager (che è il provider JPA 2.0 che delega a Hibernate Core), richiede Javassist e, quindi, dovrebbe essere nel classpath di Hibernate, consentendo la tessitura a runtime delle classi.È possibile confermare questo impostando un punto di interruzione (in un debugger remoto collegato al server delle applicazioni) e noterete che un'istanza gestita da Hibernate della classe User non conterrà un riferimento a un'istanza AvatarImage; piuttosto conterrebbe un riferimento a una classe avanzata con un nome come <package_name>.AvatarImage_$$_javassist_0 (che è il proxy che consente il recupero pigro).

Problemi correlati