Hibernate (JPA) come eseguire una query desiderosa, caricando tutti gli oggetti figlio

StackOverflow https://stackoverflow.com/questions/70992

  •  09-06-2019
  •  | 
  •  

Domanda

Relativo al mio domanda precedente, voglio assicurarmi che tutti gli oggetti figlio vengano caricati poiché ho più thread che potrebbero dover accedere ai dati (e quindi evitare eccezioni di caricamento lento).Capisco che il modo per farlo è utilizzare la parola chiave "fetch" nella query (EJB QL).Come questo:

select distinct o from Order o left join fetch o.orderLines

Supponendo un modello con an Order classe che ha un insieme di OrderLines dentro.

La mia domanda è che la parola chiave "distinto" sembra essere necessaria, altrimenti mi sembra di recuperare an Order per ciascuno OrderLine.Sto facendo la cosa giusta?

Forse ancora più importante, esiste un modo per attirare tutti gli oggetti secondari, non importa quanto siano profondi?Abbiamo circa 10-15 lezioni e per il server avremo bisogno che tutto sia caricato...Stavo evitando di usare FetchType.EAGER poiché ciò significa che è sempre desideroso e in particolare il front-end web carica tutto - ma forse è questa la strada da percorrere - è questo quello che fai?Mi sembra di ricordare che l'abbiamo provato prima e poi abbiamo ottenuto pagine web molto lente, ma forse questo significa che dovremmo utilizzare una cache di secondo livello?

È stato utile?

Soluzione

Cambiare l'annotazione è una cattiva idea IMO.Poiché non può essere modificato in pigro in fase di esecuzione.Meglio rendere tutto pigro e recuperarlo secondo necessità.

Non sono sicuro di aver compreso il tuo problema senza mappature.Il recupero del join sinistro dovrebbe essere tutto ciò che ti serve per il caso d'uso che descrivi.Ovviamente riceverai un ordine per ogni riga d'ordine se la riga d'ordine ha un ordine come genitore.

Altri suggerimenti

Non sono sicuro di utilizzare la parola chiave fetch nel tuo EJBQL, potresti confonderla con l'annotazione...

Hai provato ad aggiungere la proprietà FetchType al tuo attributo di relazione?

@OneToMany(fetch=FetchType.EAGER)?

Vedere:

http://java.sun.com/javaee/5/docs/api/javax/persistence/FetchType.html http://www.jroller.com/eyallupu/entry/hibernate_exception_simultaneously_fetch_multiple

Hai provato a utilizzare un trasformatore di risultati?Se utilizzi le query Criteri, puoi applicare un trasformatore di risultati (sebbene ci sono alcuni problemi con l'impaginazione e il trasformatore dei risultati):

Criteria c = ((Session)em.getDelegate()).createCriteria(Order.class);
c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
c.list();

IL em.getDelegate() è un trucco che funziona solo se usi l'ibernazione.

Forse ancora più importante, c'è un modo per attirare tutti gli oggetti per bambini, non importa quanto profondo?Abbiamo circa 10-15 classi e per il server avremo bisogno di tutto caricato ...Stavo evitando di usare fetchtype.eager come ciò significava che è sempre desideroso e in particolare il front -end web carica tutto - ma forse è quella di andare - è quello che fai?Mi sembra di ricordare che abbiamo provato questo prima e poi ottenere pagine Web davvero lente - ma forse ciò significa che dovremmo usare una cache di secondo livello?

Se sei ancora interessato, ho risposto ad una domanda simile in questo thread come serializzare le raccolte di ibernazione.

Fondamentalmente usi un'utilità chiamata apripista che mappa i bean su un altro bean e così facendo attivi tutti i tuoi carichi pigri.Come puoi immaginare, funziona meglio se tutte le raccolte vengono recuperate con entusiasmo.

Potresti essere in grado di fare qualcosa del genere utilizzando una query di criteri (distaccata) e impostando la modalità di recupero.Per esempio.,

Session s = ((HibernateEntityManager) em).getSession().getSessionFactory().openSession();
DetachedCriteria dc = DetachedCriteria.forClass(MyEntity.class).add(Expression.idEq(id));
dc.setFetchMode("innerTable", FetchMode.JOIN);
Criteria c = dc.getExecutableCriteria(s);
MyEntity a = (MyEntity)c.uniqueResult();

Funzionerebbe solo per le relazioni ManyToOne e per loro probabilmente @ManyToOne(fetch=FetchType.EAGER) sarebbe appropriato.

Il recupero di più di una relazione OneToMany con entusiasmo è scoraggiato e/o non funziona, come puoi leggere nel collegamento pubblicato da Jeremy.Pensa solo all'istruzione SQL che sarebbe necessaria per eseguire un simile recupero...

Quello che ho fatto è rifattorizzare il codice per mantenere una mappa di oggetti per i gestori di entità e ogni volta che devo aggiornare, chiudere il vecchio gestore di entità per l'oggetto e aprirne uno nuovo.Ho usato la query precedente senza il andare a prendere poiché questo sta andando troppo in profondità per le mie esigenze - semplicemente facendo un semplice join si inseriscono OrderLines - the andare a prendere lo fa andare ancora più in profondità.

Ci sono solo pochi oggetti per i quali ne ho bisogno, circa 20, quindi penso che il sovraccarico delle risorse nell'avere 20 gestori di entità aperti non sia un problema, anche se i DBA potrebbero avere una visione diversa quando questo sarà attivo...

Ho anche rielaborato le cose in modo che il db funzioni sul thread principale e abbia il gestore entità.

Chris

Se il problema riguarda solo LazyInitializationExceptions, puoi evitarlo aggiungendo un OpenSessionInViewFilter.
Ciò consentirà il caricamento degli oggetti nella vista, ma non aiuterà con il problema della velocità.

     <filter>
        <filter-name>hibernateFilter</filter-name>
        <filter-class> org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
        </filter-class>
    </filter>
    <filter-mapping>
        <filter-name>hibernateFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top