Programmazione Java Avanzata
Hibernate (Parte 2)
Ing. Giuseppe D'Aquì
Testi Consigliati
●
Beginning Hibernate 2nd edition (Apress)
●
●
Sul sito è possibile scaricare, tra gli “extra”, il
codice sorgente e il capitolo 3
Hibernate Getting Started
●
http://docs.jboss.org/hibernate/core/3.6/quickstart/e
2
Pro e contro Annotations
●
Pro:
●
●
Le annotation sono standard JPA, quindi sono usate
in modo identico da tutti gli ORM JPA-compatibili
●
Meno verbosità
●
Intuitive
Contro:
●
●
Le versioni obsolete di Hibernate supportano solo
XML
Se il database è usato da più applicazioni, si rischia
3
di distribuire il mapping su applicazioni diverse
Chiave Composta
●
●
Se in una tabella la chiave primaria è
costituita da più campi, si ha una chiave
composta
Quando non ci sono particolari vincoli (ovvero
abbiamo il controllo dello schema del
database), in genere si preferisce semplificare
lo sviluppo generando una chiave surrogata
●
Una chiave surrogata non ha significato al di fuori
del database, è un campo che rimpiazza i molti
campi della chiave composta
4
Chiave Composta
●
●
Quando però ci sono vincoli la chiave
composta deve essere mappata su Hibernate
Ci sono tre modalità, tutte e tre prevedono la
creazione di una classe che contenga il
mapping dei campi della chiave composta
●
Es. se la chiave composta è (nome, cognome),
allora serve una classe (differente dalla corrente)
che contenga come variabili membro String nome e
String cognome
5
Chiave composta: modo 1
●
La classe con gli attributi chiave deve essere
pubblica ed esterna
●
●
●
public class UserPrimaryKey{...}
La classe va annotata con @Embeddable, e
devono essere implementati i metodi
hashCode() ed equals()
Nella classe originaria, invece, bisogna
sostituire gli attributi della chiave composta
con un unica variabile “id” (annotata con @Id)
●
private UserPrimaryKey id;
6
Chiave composta: modo 2
●
●
●
La classe con gli attributi chiave va creata
come nel modo 1, ma internamente alla classe
originaria
La classe non va annotata con @Embeddable
La classe originaria ha sempre la variabile “id”
ma annotata con @EmbeddedId
7
Chiave composta: modo 3
●
●
La classe con gli attributi chiave va creata
come nel modo 2
Si annota solo la classe originaria con
●
●
Passandogli la classe che fa le funzioni di
chiave
●
●
@IdClass
@IdClass(User.UserPrimaryKey.class)
Nella classe originaria non c'è più “id” ma
vanno messi gli attributi originali annotati con
8
@Id
Chiave composta: riassunto
●
Il codice SQL generato in tutti i casi è uguale
●
Ci sono particolarità di utilizzo:
●
●
●
Modo 1: La classe con gli attributi è esterna
ed embeddable (vedi relazioni one-to-one),
può essere riutilizzata
Modo 3: possiamo utilizzare gli attributi
chiave direttamente dalla classe originaria
[getNome() e getCognome()], invece di
ottenere prima l'oggetto id
Modo 2: una via di mezzo
9
Mapping di relazioni
●
Le relazioni tra tabelle possono essere di
diverso tipo
●
One-to-One (uno-a-uno)
●
One-to-Many (uno-a-molti)
●
Many-to-Many (molti-a-molti)
10
One-to-one: tipi
●
Le relazioni uno-a-uno, in Hibernate, sono di
due tipi:
●
●
“Classiche”, due tabelle corrispondono a
due oggetti
“Component” o “embedded”, due oggetti
che risiedono su una sola tabella (es.
l'indirizzo)
11
One-to-one “embedded”
●
●
●
Una relazione “one-to-one embedded” si ha
quando un'entità è interamente racchiusa
all'interno di un'altra entità, ossia è un
“componente” dell'alltra entità
La classe “componente” va annotata con
@Embeddable, non possiede @Id
Nella classe principale viene posta una
variabile membro con lo stesso tipo della
classe componente, annotata con @Embedded
12
One-to-one “embedded”
public class User {
…
@Embedded
public Address getAddress(){...}
}
@Embeddable
public class Address{
private String via;
private String civico;
//getters/setters
13
}
One-to-one
●
La relazione uno-a-uno convenzionale è in
genere “sospetta”, perché potrebbe
nascondere un errore di progettazione
●
●
Ci sono dei casi in cui, però, è preferibile
avere due tabelle che rappresentano due
aspetti differenti di una certa entità “ideale”
●
●
In genere, infatti, si tende ad accorpare tutti gli
attributi in una sola entità
Aspetti che devono essere gestiti differentemente,
o che devono evolvere in modo indipendente
Es. Profilo Autenticazione e Anagrafiche
14
One-to-one
●
Per mappare una relazione uno-a-uno basta
annotare con @OneToOne la variabile membro
(o il getter) che contiene l'oggetto correlato
15
One-to-one “classica”
public class User {
…
@OneToOne
public Address getAddress(){...}
}
@Entity
public class Address{
@Id
private int id;
private String via;
private String civico;
//getters/setters
}
16
One-to-one
●
L'annotazione @OneToOne può avere i seguenti
attributi:
●
●
●
cascade: indica se le operazioni su una entità
devono propagarsi alle altre della relazione
fetch: indica il tipo di acquisizione, “eager”
(carica tutti gli oggetti del grafo delle relazioni) o
“lazy” (carica gli oggetti correlati solo se servono)
optional: serve per stabilire se ci possono essere
NULL
17
One-to-one bidirezionale
●
La relazione OneToOne è bidirezionale quando
l'oggetto A contiene un riferimento all'oggetto
B, e l'oggetto B contiene un riferimento
all'oggetto A
●
●
In questo caso uno dei due oggetti deve essere
considerato “principale”
●
●
Es. User.getAddress() e Address.getUser()
Quello la cui tabella contiene la chiave primaria
dell'altro come riferimento
L'oggetto secondario dovrà usare l'attributo
“mappedBy” nella sua annotazione
@OneToOne
18
One-to-one “bidirezionale”
@Entity
public class User {
… //User è l'oggetto “principale”
@OneToOne
public Address getAddress(){...}
}
@Entity
public class Address{
… //Address è l'oggetto “secondario”
//il “mappedBy” si riferisce alla proprietà dell'oggetto principale
@OneToOne(mappedBy=address)
public User getUser(){...}
}
19
One-to-one - JoinColumn
●
Per default, Hibernate cercherà come foreign
key un campo della tabella con queste
caratteristiche:
●
●
●
●
Inizia con il nome della proprietà dell'oggetto
principale (User ha getAddress(), quindi “address”)
Concatenato con underscore “_”
Concatenato con il nome della chiave primaria
dell'oggetto secondario (Es, Address ha getId(),
quindi “id”
Nell'esempio quindi cercherà una colonna
chiamata “address_id”
20
One-to-one - JoinColumn
●
È possibile sovrascrivere questo default con
due tipi di annotazioni:
●
●
@PrimaryKeyJoinColumn : usato assieme a
@OneToOne sull'oggetto principale, indica che la
foreign key è la stessa chiave primaria (ovvero, le
due tabelle possiedono la stessa chiave primaria)
@JoinColumn(name=”address_fk”) : usato assieme
a @OneToOne sull'oggetto principale, indica che la
foreign key sta in una colonna con un nome preciso
(in questo caso “address_fk”)
21
Cascading delle operazioni
●
Il cascading è la propagazione delle operazioni
di aggiornamento e rimozione su oggetti
collegati tra loro da relazioni
●
●
●
Esempio: se viene cancellato un User deve essere
cancellato il corrispondente Address?
Hibernate definisce diversi tipi di cascading,
definiti nelle relazioni
Se non si specifica niente, per default non si
ha cascading
22
Cascading delle operazioni
●
Tipi di cascading:
●
●
●
●
●
●
CascadeType.MERGE : propaga gli UPDATE
CascadeType.PERSIST : propaga il primo
inserimento (INSERT)
CascadeType.REFRESH : propaga l'aggiornamento
dal database verso gli oggetti (SELECT)
CascadeType.DETACH : propaga la rimozione
dell'oggetto dalla persistenza
CascadeType.REMOVE : propaga la rimozione dei
dati dell'oggetto (DELETE)
CascadeType.ALL : tutti i precedenti
23
One-to-Many
●
La relazione uno-a-molti può essere vista da
due “prospettive” diverse
●
●
●
L'oggetto A ha una relazione con molti oggetti B
Ogni oggetto B ha una relazione con uno e un solo
oggetto A
Hibernate mappa queste due prospettive
usando @OneToMany e @ManyToOne
24
One-to-Many
●
@OneToMany va sull'oggetto che contiene
●
@ManyToOne va sull'oggetto contenuto
●
JPA considera, per convezione, “oggetto
principale” quello che ha @ManyToOne che,
quindi, dovrà specificare un mappedBy
25
One-to-Many
@Entity
public class User {
… //User è l'oggetto “secondario”
@OneToMany(mappedBy=”user”)
public Set<Telephone> getTelephone(){...}
}
@Entity
public class Telephone{
… //Telephone è l'oggetto “principale”
@ManyToOne
public User getUser(){...}
}
26
One-to-Many - JoinColumn
●
●
●
Valgono le stesse considerazioni di JoinColumn
fatte nel caso One-to-One
Nell'esempio Hibernate cercherà una colonna
chiamata “user_id” nella tabella “telephone”
(oggetto principale)
Possiamo però specificare un'altra colonna
utilizzando @JoinColumn insieme a
@ManyToOne nell'oggetto principale
27
Ordering
●
●
Quando vengono mappate delle Collection,
possiamo definire una colonna sulla quale
queste verranno ordinate
●
@OneToMany(mappedBy=”user”)
●
public List<Telephone> getTelephone(){...}
●
//List è un tipo collection ordinato
Si può aggiungere a @OneToMany l'annotazione
@OrderBy, che permette di specificare quale
proprietà di Telephone usare per l'ordinamento
●
@OneToMany(mappedBy”user”)
●
@OrderBy(“prefisso ASC”)
●
public List<Telephone> getTelephone(){...}
28
Many-to-Many
●
●
●
In una relazione Many-to-Many entrambi gli
oggetti coinvolti utilizzeranno @ManyToMany
Uno dei due deve essere l'oggetto principale,
l'altro conterrà l'attributo “mappedBy”
Una relazione molti-a-molti nel modello
relazionale ha bisogno di una tabella ausiliaria
che contiene le foreign key di entrambe le
tabelle
29
Many-to-Many
●
La tabella ausiliaria ha, per default, il nome:
●
●
●
Tabellaprincipale_Tabellasecondaria
E chiavi Tabellaprincipale_id e
Tabellasecondaria_id
Questi default possono essere sovrascritti con
@JoinTable, usato lato oggetto principale
@JoinTable(
name=”studenti_e_corsi”,
joinColumns={@JoinColumn(name=”corso_id”)},
inverseJoinColumns{@JoinColumn(name=”matricola”)} )
30
Many-to-Many: nota bene
●
Quando c'è una relazione molti-a-molti che
contiene attributi specifici, forse non si tratta
di una mera relazione tra tabelle ma è una
entità “di fatto”
●
●
Es. se la tabella Studente_Corso contiene
l'attributo “voto”, non è più una semplice
tabella di join ma un'entità Esame, che ha
relazioni uno-a-molti con Studente e con
Corso
La tabella di join, per Hibernate, contiene solo
31
le foreign key e non altri attributi
Ereditarietà
●
L'ereditarietà in Hibernate e JPA può essere
rappresentata in tre modi:
●
●
●
Single table: una singola tabella che contiene padri
e figli
Joined: una tabella per il padre e una per ciascuno
dei figli, ma i figli contengono solo gli attributi non
in comune con il padre
Table-per-class: tabelle complete per ogni figlio
32
Ereditarietà: single table
●
●
●
Single table prevede una singola tabella per i
padri e per i figli
Una singola tabella contiene più
specializzazioni di una stessa entità base: gli
attributi di un figlio non avranno senso nel
caso di un “fratello” (e saranno quindi NULL)
La strategia single table si usa annotando la
classe padre con
●
@Inheritance(strategy= SINGLE_TABLE)
33
Ereditarietà: single table
●
●
Quando si usa una singola tabella per tutta la
gerarchia, bisogna specificare una “colonna
discriminante” che contiene informazioni sul
tipo dell'oggetto
Si aggiunge @DiscriminatorColumn nelle
annotazioni della classe padre
●
@Entity
●
@DiscriminatorColumn(name=”tipologia”)
●
public class Padre {...}
34
Ereditarietà: single table
●
●
Per default Hibernate, come discriminante,
crea/cerca una colonna chiamata DTYPE di
tipo stringa
Questo default può essere sovrascritto:
●
●
discriminatorType: può essere
–
DiscriminatorType.STRING
–
DiscriminatorType.CHAR
–
DiscriminatorType.INTEGER
lenght: la lunghezza del campo, usata solo nel caso
stringa
35
Ereditarietà: single table
●
●
I valori contenuti nella colonna discriminante
sono, per default, i nomi delle classi figlio
Volendo usare valori differenti si dovranno
annotare le classi figlio con
@DiscriminatorValue(“valore”)
36
Ereditarietà: Joined
●
●
●
Le annotazioni sono identiche al caso Single
Table
C'è @DiscriminatorColumn,
@DiscriminatorValue eccetera
Si attua annotando la classe padre con
●
●
●
@Inheritance(strategy = JOINED)
A basso livello Hibernate creerà/cercherà una
tabella per il padre...
...e una tabella per ogni figlio, che conterrà
soltanto gli attributi che non sono già presenti
37
nel padre
Ereditarietà: Table Per Class
●
●
Con questa strategia, tutti gli oggetti (padre e
figli), se concreti, avranno tabelle che
contengono tutti i loro attributi
Basta annotare la classe padre con
●
@Inheritance(strategy = TABLE_PER_CLASS)
38
Ereditarietà: Quale Strategia?
●
●
●
Usando Joined si avrà uno schema più
mantenibile, perchè ogni modifica di un figlio
impatta solo sulla tabella del figlio, e ogni
modifica al padre impatta solo sulla tabella
padre
Usando table-per-class, ogni modifica al padre
impatterà anche su tutte le tabelle dei figli –
mentre le performance sono migliori del caso
Joined, perché non ci sono join
Single Table ha migliori performance, perché
tutte le query vengono fatte su una sola
tabella, ma può diventare disordinata
39
Mapped Superclass
●
●
Un caso speciale di ereditarietà si ha quando
la classe padre non è resa persistente e quindi,
in teoria, non dovrebbe possedere annotazioni
Hibernate
In realtà per far funzionare l'ereditarietà
dovremo annotare la classe padre come se
fosse persistente, e poi aggiungere
●
●
@MappedSuperClass
Subito dopo @Entity, per specificare che la
classe padre è solo mappata e non deve essere40
resa persistente
Altre annotazioni
41
Dati temporali
●
●
Le proprietà di tipo java.util.Date vengono di
default mappate su attributi di tipo TIMESTAMP
Questo comportamento può essere modificato
con l'annotazione @Temporal
●
@Temporal(TemporalType.DATE)
●
@Temporal(TemporalType.TIME)
●
@Temporal(TemporalType.TIMESTAMP)
42
Large Objects
●
●
●
I Large Objects sono attributi di una tabella
che contengono oggetti molto grandi:
●
stringhe estese (LONGTEXT)
●
sequenze di byte (BLOB, Binary Large OBject)
Per specificare che una certa proprietà va
salvata in un attributo di tipo large, basta
annotarla con @Lob
●
@Lob
●
public String getTitle() { … }
Si creerà un attributo che non sarà varchar
43
Generare Indici
●
●
Questa è una annotazione non inclusa in JPA,
solo in Hibernate
Gli indici possono essere applicati:
●
Alla singola colonna, con l'annotazione
–
●
@Index(name=”nomedellindice”)
Su diverse colonne contemponaneamente,
annotando la classe con:
@Table(appliesTo=”nometabella”, indexes = {
@Index(name=”nomeindice1”, columnNames={“col1”, “col2”}
})
44
Named Query
●
●
●
Una Named Query è una query (in HQL) a cui
diamo un nome, per poter essere richiamata
successivamente
È composta quindi da una coppia (nome,
espressione)
Si definisce con annotazione di classe:
@Entity
@NamedQuery(name=”findAllStudents”,
query=”from Students”)
public class Student{ … }
45
Named Query
●
●
●
La caratteristica delle Named Query è quella
di essere riutilizzabili
Se vogliamo riutilizzarle tra più classi,
dobbiamo definirle a livello di package
Si crea un file chiamato package-info.java che
conterrà le annotazioni che devono essere
condivise tra tutte le classi del package
@NamedQuery(name=”findAllStudents”,
query=”from Students”)
package it.unirc.pja.example2
46
Hibernate Console
47
Hibernate Console
●
●
La Hibernate Console è un tool che fa parte
del plugin per Eclipse
Permette di svolgere le seguenti funzioni
●
●
●
●
Visualizzazione rapida dei mapping e degli schemi
Scrittura di query di test HQL (parametrizzate e
non)
Generazione dello schema del database a partire
dai mapping
Generazione di diagrammi che rappresentano i
mapping
48
Hibernate console: esempio
●
Vedi
49
Metodi base di Session
50
Metodi base di Session
●
●
●
Abbiamo già visto che l'oggetto Session è
fondamentale
Svolge la funzione di interfaccia tra i nostri
oggetti Java e Hibernate
Session ha un certo numero di metodi utilizzati
per richiamare le funzionalità di Hibernate
51
Salvataggio
●
●
Quando si crea un nuovo oggetto che possiede
mapping Hibernate, questo non viene
automaticamente reso persistente
Si deve salvare per la prima volta in una
Session, tramite il metodo save()
●
session.save(oggetto);
●
52
Nota Bene: Confronto
●
Un certo oggetto reso persistente avrà due modi per
essere identificato:
●
●
●
●
Identificativo di istanza della classe (che rappresenta
l'oggetto)
Chiave primaria (che rappresenta la tupla)
Nell'ambito di una stessa sessione entrambi gli
identificativi potranno essere usati, mentre su più
sessioni l'identificativo di istanza potrebbe cambiare
Bisogna quindi evitare di usare l'operatore == (che
confronta l'identificativo di istanza); meglio usare
equals(), magari implementata da noi con il confronto tra
53
le primary key
Caricamento
●
●
Il caricamento di oggetti persistenti avviene
tramite load()
Ha due parametri:
●
●
●
●
La classe della entity, passata come nome (String)
o come oggetto Class
L'id dell'oggetto (chiave primaria)
Se la chiave specificata non esiste verrà
lanciata una eccezione
Simile a load() è get(): se la chiave non esiste
restituisce NULL invece di una eccezione
54
Caricamento: Lock modes
●
●
●
●
Sia load() che get() supportano un terzo
parametro, opzionale, che serve a specificare
il lock degli oggetti caricati
Il lock è usato per evitare problemi di
aggiornamento concorrente
I lock vengono rilasciati alla fine della
transazione
Attenzione: usare i lock può creare problemi di
deadlock, se più thread in contemporanea
acquisiscono parte delle risorse e non le
55
rilasciano (vedi Problema dei 5 filosofi)
Caricamento: Lock modes
●
Lock mode disponibili:
●
●
●
●
NONE: default; legge dal database solo se l'oggetto
richiesto non è in cache
READ: legge semre l'oggetto dal database
UPGRADE: se supportato dal database/dialect,
imposta un lock di aggiornamento; se non è
possibile ottenerlo, attende che vengano rilasciati
i lock che ostacolano
UPGRADE_NOWAIT: come UPGRADE, ma se non è
possibile ottenere il lock lancia subito una
eccezione
56
Aggiornamento dal DB
●
●
Se vogliamo ottenere l'ultima versione
dell'oggetto dal database (eliminando le
modifiche fatte da noi) basta utilizzare il
metodo refresh()
In realtà Hibernate nella maggior parte dei
casi lo fa in automatico, non c'è bisogno di
chiamare refresh() direttamente
●
Il caso particolare si ha quando l'oggetto viene
aggiornato da applicazioni esterne oppure da query
SQL: in questo caso Hibernate non può sapere che
57
l'oggetto è stato aggiornato
Update
●
●
●
Se un oggetto è persistente, ogni modifica che
operiamo su di esso viene “accodata” ed
eseguita da Hibernate alla fine della sessione
Non è necessario eseguire esplicitamente una
operazione di update (con il metodo update())
Nel caso volessimo salvare tutte le operazioni
effettuate sul db prima del termine della
sessione, possiamo usare il metodo flush()
58
Update: flush() modes
●
●
La strategia di flushing “automatica” prevede
di salvare ogni oggetto prima di eseguire una
query che restituisce l'oggetto stesso
Esistono altre strategie, impostabili con
setFlushMode():
●
●
●
ALWAYS: prima di ogni query effettua flush(),
salvando tutti gli oggetti. Lento
COMMIT: esegue flush() solo in fase di commit
MANUAL: non esegue mai flush(), dobbiamo
richiamarlo esplicitamente nel codice
59
Delete
●
●
Se si deve cancellare un oggetto persistente si
può usare il metodo delete()
Il parametro di delete() è un Object, che può
essere:
●
●
L'oggetto da cancellare
Un oggetto dello stesso tipo di quello da
cancellare, con la proprietà chiave impostata
(questo si usa se non abbiamo l'oggetto completo
ma conosciamo solo l'id)
60
SaveOrUpdate()
●
●
●
●
Il metodo save() rende persistente un oggetto
(INSERT) mentre update() lo aggiorna (UPDATE)
La prima volta va usato save(), le successive
update()
Se la prima volta si usa update(), o nelle
successive save(), ci sarà un errore
Se non sappiamo se usare save() o update(),
possiamo usare saveOrUpdate() che effettua
una select per vedere se l'oggetto esiste, e poi
chiama save() o update()
61
Disassociazione
●
●
●
Può capitare di aver bisogno che un certo
oggetto non sia più persistente
Dato che ogni modifica dentro una sessione
viene tracciata da Hibernate, per poi eseguire
gli aggiornamenti, vorremmo evitare che
venissero tracciate operazioni che non vanno
riportate sul database
In questo caso si usa il metodo evict(), che
disassocia un oggetto dalla sessione corrente
62
Hibernate Query Language
63
Sintassi base
●
●
●
Hibernate fornise un proprio linguaggio di
query, basato suglio oggetti e modellato in
modo molto simile a SQL
Poiché dall'interno di Hibernate si possono
sfruttare le informazioni di mapping, molte
delle query in HQL sono più compatte delle
corrispondenti versioni SQL
Ovviamente, HQL viene tradotto in SQL prima
di essere inviato al database
64
Sintassi base
●
●
●
SELECT
È identico all'equivalente SQL, solo che la
parte di proiezione (SELECT nome, cognome) è
opzionale: se non si specifica si assume
“SELECT *”
La clausola FROM è seguita dal nome di una
classe, piuttosto che di una tabella
65
CreateQuery
●
Un oggetto di tipo Query può essere ottenuto,
a partire dalla corrispondente stringa HQL,
tramite il metodo createQuery() di Session
●
Query q = session.createQuery(“from User”);
66
Controllare codice SQL generato
●
●
●
Il codice HQL viene convertito in SQL prima di
essere inviato al database
Può capitare che, in alcuni casi, la traduzione
sia una query SQL inefficiente
Possiamo visualizzare le traduzioni tramite:
●
●
Hibernate console in Eclipse
File di Log, se abilitiamo la proprietà “show_sql”
nel file di configurazione di Hibernate
67
Filtri condizionali
●
●
●
Ovvero la clausola WHERE
Possiamo usare tutti gli operatori tipici di SQL
(OR, AND, =, <>, like eccetera)
In più possiamo definire dei parametri, per
realizzare query parametriche
●
I parametri si inseriscono come :nomeparametro
●
Es: “From User where name=:name”
68
Named Parameters
●
●
I Named Parameters ci aiutano a difendere la
nostra applicazione dagli attacchi di SQL
Injection
Infatti la sostituzione tra parametri e valore
effettivo avviene controllando il tipo esatto
dell'oggetto passato
●
Es.
–
Query query = session.createQuery(“from User where
address=:address”);
–
query.setEntity(“address”, myAddress);
69
Pagination
●
●
●
Normalmente in una web application
restituiremo solo un certo numero di dati
all'utente
Se sono molti, questo significa mostrare una
pagina alla volta
L'oggetto query possiede due metodi per
supportare questa funzionalità:
●
setFirstResult(int) : indica la tupla di partenza
●
setMaxResults(int) : indica quante tuple prelevare
70
Risultato unico
●
●
●
●
L'oggetto Query ha un metodo list() che
restituisce tutti i risultati di una query
Possiede anche un metodo uniqueResult() che
restituisce solo un oggetto
Se l'oggetto è più di uno, lancia una eccezione
Quando vogliamo ottenere solo il primo
risultato, dovremo usare una combinazione di
uniqueResult() e setMaxResults(1)
Order by
●
●
●
HQL supporta la clausola Order By che viene
usata come in SQL
“order by nomeproprietà [desc|asc]”
Se vogliamo ordinare per più proprietà, basta
separarle con la virgola
Join
●
●
Tramite le join si possono usare più classi in
una sola query
Hibernate supporta più tipi di join:
●
●
Inner, cross, left outer, right outer, full outer
Se ci sono i mapping non c'è bisogno di
specificare le condizioni di join
Aggregazioni
●
HQL supporta gli operatori di aggregazione:
●
avg(name)
●
count(name|*)
●
max(name)
●
min(name)
●
sum(name)
Aggiornamenti in blocco
●
●
●
Quando serve aggiornare o cancellare un certo
numero di oggetti contemporaneamente,
usare un ciclo for potrebbe essere inefficiente
Si possono usare gli equivalenti HQL di UPDATE
e DELETE
Basta creare una query di update/delete, e
poi chiamarne il metodo executeUpdate()
SQL Nativo
●
L'uso di SQL nativo si dovrebbe evitare per
ottenere la massima portabilità; se proprio è
necessario, possiamo creare una query in SQL
utilizzando il metodo
●
Session.createSQLQuery(String)