2.1 opzione di recupero
Gli sviluppatori di Hibernate conoscono da tempo il problema con il caricamento di entità figlie. Quindi la prima cosa che hanno fatto è stata aggiungere uno speciale parametro fetch alle annotazioni @OneToMany
, @ManyToMany
.
Questo parametro può assumere due valori:
- DESIDEROSO
- PIGRO
Esempio:
@OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
Se il parametro fetch è uguale a EAGER , quando viene caricata l'entità padre, verranno caricate anche tutte le sue entità figlio. Inoltre, Hibernate proverà a farlo in una query SQL, generando una query pesante e ottenendo tutti i dati contemporaneamente.
Se il parametro fetch assume il valore LAZY , quando viene caricata l'entità padre, l'entità figlio non verrà caricata. Verrà invece creato un oggetto proxy.
Con l'aiuto di questo oggetto proxy, Hibernate monitorerà l'accesso a questa entità figlio e lo caricherà in memoria la prima volta che vi si accede.
Se ricordiamo la nostra situazione con commenti:
@Entity
@Table(name="user")
class User {
@Column(name="id")
public Integer id;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
public List<Comment> comments;
}
Allora hai una “scelta chic”:
Se fetch = FetchType.EAGER
, Hibernate caricherà tutti i commenti sulla prima riga di codice:
User user = session.get(User.class, 1); //load all comments here
List<Comment> comments = user.getComments();
Se fetch = FetchType.LAZY
, Hibernate caricherà tutti i commenti sulla seconda riga di codice:
User user = session.get(User.class, 1);
List<Comment> comments = user.getComments(); //load all comments here
Come puoi già intuire, non hai alcuna opzione quando non carica tutti i commenti :)
2.2 Valore predefinito
Se non specifichi un'opzione di recupero per l' @ManyTo
annotazione ..., Hibernate utilizzerà i valori predefiniti.
Sono leggermente diversi per i diversi tipi di annotazione. Per le annotazioni @OneToOne
ed @ManyToOne
è EAGER, per le annotazioni @OneToMany
ed @ManyToMany
è PIGRO. È facile da ricordare: se ci riferiamo a un oggetto, verrà caricato completamente. Se ci riferiamo a una raccolta, verrà caricata al primo accesso.
2.3 Annotazione @LazyCollection
Come hai già visto, il parametro fetch non aiuta molto quando si lavora con le raccolte. I creatori di Hibernate hanno provato a risolvere questo problema aggiungendo un'annotazione speciale @LazyCollection
. Di solito si scrive così:
@LazyCollection(LazyCollectionOption.TRUE)
È necessario specificarlo durante la mappatura dei campi della raccolta:
@Entity
@Table(name="user")
class User {
@Column(name="id")
public Integer id;
@OneToMany(cascade = CascadeType.ALL)
@LazyCollection(LazyCollectionOption.TRUE)
public List<Comment> comments;
}
Questa annotazione ha un parametro di valore che può assumere uno dei tre valori:
- Opzione LazyCollection. VERO
- Opzione LazyCollection. FALSO
- Opzione LazyCollection. EXTRA
Le prime due opzioni sono molto simili all'opzione fetch.
Se il parametro è impostato su LazyCollectionOption.TRUE
, significa che i valori del campo dei commenti non verranno caricati dal database quando viene caricato l'oggetto utente padre. Gli oggetti di tipo Comment verranno caricati la prima volta che si accede al campo dei commenti. In effetti, questo è l'equivalente del parametroFetchType.LAZY
Se il parametro è impostato su LazyCollectionOption.FALSE
, significa che i valori del campo dei commenti verranno caricati dal database al momento del caricamento dell'oggetto utente padre. Gli oggetti di tipo Comment verranno caricati la prima volta che si accede al campo dei commenti. In realtà, questo è l'equivalente di FetchType.EAGER
.