2011-01-26 21 views
9

Sto riscontrando un problema in cui JPA sta tentando di caricare i dati con pigrizia quando non lo desidero. Essenzialmente ciò che sta accadendo è che sto usando un servizio per recuperare alcuni dati, e quando vado ad analizzare i dati in JSON, la libreria JSON sta attivando la sospensione per provare a caricare i dati con pigrizia. C'è un modo per fermare questo? Ho dato un esempio qui sotto.JPA2/Hibernate - Arresta il caricamento lento?

// Web Controller method 
public String getEmployeesByQuery(String query) { 

    Gson gson = new Gson(); 
    List<Employee> employees = employeeService.findEmployeesByQuery(query); 

    // Here is where the problem is occurring - the gson.toJSON() method is (I imagine) 
    // using my getters to format the JSON output, which is triggering hibernate to 
    // try and lazily load my data... 
    return gson.toJSON(employees); 
} 

E 'possibile impostare JPA/ibernazione di non cercare di pigramente caricare i dati?

AGGIORNAMENTO: Mi rendo conto che è possibile utilizzare FetchType.EAGER - ma cosa succede se non desidero caricare quei dati? Voglio solo interrompere l'ibernazione dal tentativo di recuperare più dati - ho già i dati che voglio. In questo momento ogni volta che provo ad accedere a un metodo get(), l'hibernate genera un errore "nessuna sessione o sessione è chiusa", il che ha senso perché la mia transazione è già stata trasferita dal mio servizio.

Grazie!

+0

Potresti dire di usare di più sulla tua domanda: vuoi passare completamente dal caricamento pigro al caricamento ansioso o vuoi non caricare i dipendenti pigri in questo caso specifico e perché. – gabuzo

+0

Il mio problema è che non voglio caricare pigramente i dati. Certo, potrei contrassegnarlo per il caricamento di EAGER - ma cosa succede se non mi interessa nemmeno di quei dati in questo momento? Per esempio, se ho un Dipendente che ha molte posizioni, ma non voglio quei dati perché è troppo dettagliato per la vista che voglio rendere, come faccio a dire a JPA di non provare a recuperare quei dati? –

+0

Prova questo: http://stackoverflow.com/questions/4802887/gson-how-to-exclude-specific-fields-from-serialization-without-annotations –

risposta

3

realmente avete due opzioni:

  1. è possibile copiare i dati da dipendente a uno che non è in fase di proxy da Hibernate.
  2. Vedere se esiste un modo per non avere la libreria toJSON che riflette l'intero grafico dell'oggetto.So che alcune librerie JSON consentono di serializzare solo alcune proprietà di un oggetto su JSON.

Personalmente penserei che il primo sarebbe più semplice se la libreria utilizza solo la riflessione.

+0

Sembra che queste potrebbero essere le uniche opzioni. Ma nessuno di loro non è davvero l'ideale. Si potrebbe pensare che JPA specifichi un modo per far sì che le entità distaccate non provino e recuperino più dati ... –

+0

Ho usato la sospensione e JPA e ho avuto questo problema in entrambi. Non ho mai trovato un buon modo per risolverlo. – Ruggs

0

Sì:

@*ToMany(fetch=FetchType.EAGER) 
0

Si può sempre modificare l'attributo fetch-FetchType.EAGER, ma è anche opportuno prendere in considerazione se avete il vostro transazioni hanno lo scopo destra. Le raccolte verranno caricate correttamente se vi si accede all'interno di una transazione.

6

Ci sono diverse opzioni:

  • Se avete sempre bisogno di caricare la vostra collezione con entusiasmo, è possibile specificare fetch = FetchType.EAGER nella vostra mappatura, come suggerito in altre risposte.

  • In caso contrario è possibile abilitare il caricamento diretto per la query particolare:

    • Utilizzando JOIN FETCH clausola HQL interrogazione/JPQL:

      SELECT e FROM Employee e JOIN FETCH e.children WHERE ... 
      
    • Utilizzando fetch profiles (in APP è possibile accedere Hibernate Session via em.unwrap(Session.class))
+0

Il fatto è che non voglio quei dati extra. Davvero tutto quello che voglio sono alcuni campi di base da solo dipendente (come nome, cognome, numero di telefono, ecc.) E non ho l'ibernazione provare e recuperare più dati quando non lo voglio! –

+0

@Brian: se non si desidera includere questi campi nella rappresentazione JSON, è necessario indicare al serializzatore JSON di ignorare tali campi, come suggerito da Ruggs. Non ha nulla a che fare con JPA e Hibernate. – axtavt

1

Ti suggerisco di creare una copia recuperata delle entità che desideri utilizzare al di fuori di una transazione. In questo modo, il caricamento pigro si verificherà all'interno di una transazione e potrai passare a Gson in modo semplice, non potenziato, POJO.

È possibile utilizzare Doozer per eseguire questa operazione. È molto flessibile e attraverso una piccola configurazione (leggi perderesti i capelli configurandolo come) puoi anche recuperare solo parzialmente i dati che vuoi inviare a Gson.

+0

Questa è un'opzione, ma vorrei davvero evitare di aggiungere un'altra libreria, se possibile. –

+0

Puoi farlo manualmente se vuoi utilizzare la riflessività per scoprire getter e setter ma usare una libreria ti farà risparmiare ore di sviluppo incline agli errori noiosi. – gabuzo

0

Il tuo problema è che stai serializzando i dati. Abbiamo incontrato lo stesso tipo di problemi con Flex e JPA/Hibernate. Il trucco è, a seconda di quanto vuoi manipolare,

  1. Modificare il modello di dati per non inseguire i dati che non si desidera.
  2. Copia i dati che desideri in una sorta di DTO senza relazioni di cui preoccuparsi.
  3. Supponendo che si stia utilizzando Hibernate, aggiungere il filtro Session-in-view .... è qualcosa del genere, manterrà la sessione aperta mentre serializzi l'intero database. ;)

Opzione uno è quello che abbiamo fatto per la prima grande progetto che abbiamo fatto, ma ha rovinato la libreria di accesso ai dati che abbiamo avuto per qualsiasi tipo di uso generale. Da quel momento siamo più inclini verso l'opzione due.

YMMV

2

Come altri hanno già detto, questo non è un problema con JPA/hibernate, ma piuttosto con la libreria JSON serializzazione che si sta utilizzando. È necessario instruct gson per escludere le proprietà che non si desidera attraversare.

0

La cosa semplice da fare è creare nuove classi Data (qualcosa come DTO) utilizzare Hibernate.isInitialized() per verificare se l'oggetto è inizializzato da ibernazione o meno. Sto controllando gson se riesco a scavalcare qualsiasi cosa. Lo posterò qui se trovo qualcosa di nuovo.

Problemi correlati