Sei sulla pagina 1di 25

Sessione 12

Hibernate

1
Hibernate
Hibernate è un tool Java, che è diventato uno standard de-facto per la gestione degli R-DBMS in Java.

Essenzialmente Hibernate è un tool per gestire l’ORM, Object Relational Mapping, ovvero la corrispondenza bidirezionale tra
oggetti Java e record delle tabelle degli R-DBMS. Inoltre, Hibernate tra le altre cose mette a dispozione una serie di strumenti per
l’esecuzione di istruzioni SQL e per la gestione delle transazioni su R-DBMS.

Nel corso di questa sessione ci concentreremo sui concetti di ORM, esecuzione di SQL e gestione delle transazioni in Hibernate;
inoltre, mostreremo degli esempi di applicazioni pratiche dei concetti appena enunciati attraverso il codice sorgente del progetto
“Corso”. In particolare, vedremo come far evolvere il progetto gestendo le classi del package model attraverso l’ORM di
Hibernate e introdurremo le classi del package dao in cui vedremo come lanciare istruzioni SQL e come gestire le transazioni in
Hibernate.

Hibernate è scaricabile gratuitamente dal link http://hibernate.org/orm/downloads/.

2
ORM

Come detto, per ORM, acronimo di Object Relational Mapping, si intende tutto ciò che è inerente il mapping bidirezionale tra
oggetti Java e record di tabelle del R-DBMS.

Da un’attenta osservazione delle sessioni del corso dedicate alla gestione dei database ed a Jdbc si può osservare che il modo
“concettuale” di lavorare “object oriented” è abbastanza distante dal modello “relazionale” usato dagli R-DBMS.

A riprova di ciò basti pensare che nel mondo dell’informatica sono sorte nel corso degli anni due figure tecniche distinte e
separate, che spesso e volentieri non hanno un’approfondita conoscenza l’una delle tematiche affrontate dall’altra. Stiamo
parlando delle figure dell’analista/programmatore object oriented e quello dell’analista/sviluppatore Pl-SQL.

Se guardiamo alle sessioni precedenti possiamo verificare che prima di poter salvare lo stato di un oggetto Java su database,
occorre creare la tabella sul database e poi trasformare lo stato dell’oggetto in una serie di istruzioni SQL di INSERT da lanciare
attraverso Jdbc. Tra l’altro, a seconda del tipo degli attributi della nostra classe Java occorre utilizzare istruzioni Jdbc differenti.
Stessa cosa dicasi per le istruzioni SQL di UPDATE, DELETE o per le SELECT.

Tutto questo determina la creazione di un vincolo forte tra codice SQL e codice Java. Usando Jdbc inevitabilmente il nostro
codice Java sarà pieno di stringhe che rappresentano istruzioni SQL.

3
Il problema che molti ingegneri e sviluppatori software object oriented si sono iniziati a porre già da una quindicina d’anni, era
un modo per poter sganciare il più possibile il codice Java da quello SQL; trovare, quindi, un meccanismo attraverso cui lo
sviluppatore Java non debba preoccuparsi troppo della sintassi SQL, né di concetti quali la creazione/eliminazione di una tabella
nel R-DBMS. Ecco, quindi, la necessità di sviluppare dei tool che gestissero l’ORM, consentendo quindi di disaccoppiare il
codice Java dal codice SQL. L’idea degli ORM è quella di creare un’interfaccia logica che consenta di:

• tradurre la struttura di una classe Java in una tabella del R-DBMS

• tradurre istruzioni Java in equivalenti istruzioni SQL

Giusto per esemplificare, l’obiettivo era quello di poter scrivere nel codice Java un’istruzione del tipo save(oggetto) e lasciare al
tool di gestione dell’ORM il compito di tradurla in un’opportuna istruzione INSERT in SQL.

Abbiamo parlato non a caso genericamente di tool di gestione dell’ORM, in quanto esistono anche altri tool diversi da Hibernate,
anche se, nel momento in cui scriviamo (fine 2015), quest’ultimo è senz’altro il più diffuso.

Per Hibernate l’interfaccia di disaccoppiamento di cui parlavamo prima tra il mondo ad oggetti ed il mondo SQL è rappresentata
da un file xml.

Hibernate, infatti, attraverso la propria implementazione del concetto di ORM, tra le altre cose permette di descrivere in un file
xml, la corrispondenza tra:

4
• nome della classe Java (fully qualified) e nome di una tabella del R-DBMS

• nome e tipo degli attributi di una classe Java e nome e tipo dei campi della tabella del R-DBMS

• identità di un oggetto Java e vincolo di primary key della corrispondente tabella del R-DBMS

• relazioni tra classi Java e vincoli di foreign key tra le tabelle del R-DBMS

Per convenzione il suddetto file di mapping viene nominato con estensione .hbm.xml (hbm è l’acronimo di HiBernate Mapping).

Osserviamo subito che Hibernate, opportunamente configurato è in grado di creare direttamente la tabella del database a partire
dal file xml di mapping.

Facciamo subito un esempio, relativo alla classe Aula presente nel package model del nostro progetto “Corso”.

Come visto nelle precedenti sessioni, per la classe Aula abbiamo stabilito i seguenti aspetti:

1. avrà una corrispondente tabella Aula su database

2. la primary key della tabella Aula sarà definita attraverso una chiave naturale sul campo nome, corrispettivo dell’attributo
nome della classe Aula

E questo ci ha portato a modellare la classe Aula con i seguenti vincoli:

5
1. Aula implementa l’interfaccia Serializable

2. abbiamo creato una classe-wrapper AulaId (anch’essa implementa l’interfaccia Serializable) definita come wrapper attorno
all’attibuto nome (spostato dalla classe Aula alla classe AulaId) che per noi identifica univocamente un oggetto di classe
Aula e pertanto:

1. abbiamo fatto override dei metodi equals e hashCode della classe AulaId basando l’implementazione dei due metodi
sul valore dell’attributo nome

2. nella classe Aula abbiamo definito un attributo id di tipo AulaId ed abbiamo fatto override dei metodi equals e
hashCode basando la loro implementazione sul valore dell’attributo id

Per mappare in Hibernate la relazione tra la classe Aula e la tabella Aula, scriviamo un file xml, che nomineremo Aula.hbm.xml
(dove hbm è l’acronimo di HiBernate Mapping) nel seguente modo:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.azienda.progettoCorso.model.Aula" table="Aula">
<composite-id name="id" class="com.azienda.progettoCorso.model.AulaId">
<key-property name="nome" type="java.lang.String">
<column name="nome" length="200"/>
</key-property>
</composite-id>

6
<property name="descrizione" type="java.lang.String">
<column name="descrizione" length="255"/>
</property>
</class>
</hibernate-mapping>

L’analisi dei tag del file xml di mapping è abbastanza intuitiva, ma comunque analizziamola più in dettaglio.

Tralasciamo tutti i tag precedenti <class> che rimangono invariati per qualsiasi file di mapping di Hibernate.

Il tag <class> permette di mappare il nome fully-qualified della classe, com.azienda.progettoCorso.model.Aula, con il nome
della tabella Aula. Attraverso questa istruzione, come vedremo, Hibernate sarà in grado di creare in autonomia una tabella Aula
basata sugli altri tag del nostro file Aula.hbm.xml.

Il tag <composite-id> rappresenta uno dei modi possibili per definire il mapping tra attributo/i che identificano un oggetto di
classe Aula (nel nostro caso l’attributo nome) e primary key della tabella del R-DBMS. <composite-id> è la best-practice quando
la primary key della tabella è una chiave naturale, come nel caso della tabella Aula.

Altri modi per rappresentare il mapping suddetto li vedremo più avanti, in particolare vedremo il caso in cui la primary key della
tabella è una sequence.

<composite-id name="id" class="com.azienda.progettoCorso.model.AulaId">

7
Il tag consente di definire il mapping tra nome dell’attributo della classe Java (nel nostro caso id) e nome della classe-wrapper
(nel nostro caso AulaId).

Il sotto-tag <key-property> definisce il mapping tra il nome dell’attributo della classe Java e nome del campo (o colonna) della
tabella del database:

<key-property name="nome" type="java.lang.String">


<column name="nome" length="200"/>
</key-property>

In particolare, l’attributo name di <key-property> è il nome dell’attributo della classe Java e l’attributo type specifica il tipo Java
dell’attributo.

L’ulteriore sotto-tag <column> definisce, invece, il nome della colonna (o campo) della tabella attraverso l’attributo name e la
dimensione massima del campo attraverso l’attributo length.

Terminata l’analisi del tag <composite-id>, passiamo ai tag <property>. Questi ultimi consentono di definire la corrispondenza
tra gli altri attributi della classe Java e la tabella del database e vanno interpretati allo stesso modo del sotto-tag <key-property>
del tag <composite-id>:

<property name="descrizione" type="java.lang.String">


<column name="descrizione" length="255"/>
</property>

8
Guardiamo adesso il caso del mapping tra classe Sede e tabella Sede che salveremo in un file di nome Sede.hbm.xml.

Qui di nuovo rispetto a quanto visto a proposito della tabella Aula c’è il concetto di primary key gestita attraverso una sequence
piuttosto che attraverso una chiave naturale.

<class name="com.azienda.progettoCorso.model.Sede" table="Sede">


<id name="id" type="long" column="id">
<generator class="sequence">
<param name="sequence">sede_id_sequence</param>
</generator>
</id>

Notiamo l’uso del tag <id> in luogo di <composite-id>. L’attributo name, del tag <id>, specifica il nome dell’attributo della
classe Sede, mentre l’attributo column specifica il nome della colonna (o campo) della tabella Sede; l’attributo type specifica che
l’attributo è di tipo numerico esteso long.

Il sotto-tag <generator> specifica come deve essere generata la primary-key. Tramite l’attributo class=”sequence” stiamo
indicando che la chiave primaria viene generata in automatico dal R-DBMS tramite una sequence, ovvero è un numero che stesso
l’R-DBMS garantisce sia univoco e sia incrementato ogni volta che si inserisce un record nella tabella. Quanto appena detto
implica che quando andremo a salvare una sede su database non dovremo fornire esplicitamente nel nostro codice il valore
dell’attributo id.

L’ulteriore sotto-tag <param name="sequence">sede_id_sequence</param>

9
specifica il nome che vogliamo assegnare alla sequence su database, nel nostro caso sede_id_sequence.

Infine se guardiamo il mapping relativo alle classi Corso e Soggetto potremo osservare come vengono gestite le relazioni n->1 ed
n->m in Hibernate.

Per esempio, sappiamo che la classe Corso ha una relazione n->1 con le classi Materia, Sede, Aula e Soggetto (nel ruolo di
docente). Infatti, concettualmente dato un corso avremo una sola materia di quel corso, mentre, viceversa, data una materia questa
può appartenere ad n corsi. Lo stesso dicasi per le relazioni di Corso con Sede, Aula e Soggetto (nel ruolo di docente).

In Java le precedenti relazioni sono rappresentate da altrettanti attributi della classe Corso nel seguente modo:

private Materia materia = null;


private Aula aula = null;
private Sede sede = null;
private Soggetto docente = null;

Sappiamo già da quanto detto nelle sessioni precedenti che invece lato database queste relazioni corrispondono ad altrettante
foreign key dalla tabella Corso alle tabelle Materia, Aula, Sede e Soggetto.

Nel file xml di mapping Corso.hbm.xml le suddette relazioni sono mappate attraverso i tag:

<many-to-one name="materia" class="com.azienda.progettoCorso.model.Materia" column="materia" lazy="false"/>


<many-to-one name="sede" class="com.azienda.progettoCorso.model.Sede" column="sede" lazy="false"/>
<many-to-one name="aula" class="com.azienda.progettoCorso.model.Aula" column="aula" lazy="false"/>
<many-to-one name="docente" class="com.azienda.progettoCorso.model.Soggetto" column="docente" lazy="false"/>

10
Il tag <many-to-one>, come dice il nome, rappresenta una relazione n->1. I suoi attributi sono:

• name: il nome dell’attributo della classe Java

• class: il nome della classe che rappresenta l’altro lato della relazione

• column: il nome della colonna (o campo) della tabella sul database

• lazy: vedi sotto

L’attributo lazy merita una trattazione a parte, sia perché gli altri attributi sono abbastanza intuitivi ed auto-esplicativi, sia per la
sua importanza.

Quando definiamo una relazione n->1 come ad esempio quella tra Corso e Materia, una query Hibernate che recuperi un oggetto
di classe Corso può recuperare subito anche l’oggetto di classe Materia referenziato dal corso oppure farlo on-demand, cioè solo
quando viene esplicitamente richiesto dal codice chiamante di accedere all’oggetto di classe Materia referenziato.

Se ad esempio sul database avessimo un record che rappresenta un corso di nome “corso_1” riguardante la materia “Inglese”,
una query Hibernate che recuperasse questo corso restituirebbe senz’altro un oggetto di classe Corso con nome=”corso1” mentre
l’attributo materia di corso può essere inizialmente null (ed essere popolato soltanto quando richiamiamo corso.getMateria())
oppure può essere subito popolato con l’oggetto materia con nome=”Inglese”.

11
E’ chiaramente una questione di performance: restituire l’oggetto corso senza popolare i vari attributi materia, sede, docente e
aula rende la query più veloce e se non dovremo accedere ai vari metodi corso.getMateria(), corso.getSede() etc. questo
risparmio di tempo sarà soltanto un vantaggio. Viceversa, se successivamente nel codice dovremo richiamare i suddetti metodi,
pagheremo un tempo di esecuzione della query maggiore (è come se Hibernate dovesse andare a rieseguire la query per
recuperare le foreign key).

lazy è l’opzione che discrimina il tipo di comportamento che per noi deve avere Hibernate. Tradotto in italiano, il termine “lazy”
vuol dire “pigro”, per cui “lazy=true” equivale ad istruire Hibernate di non caricare subito anche gli oggetti che rappresentano le
foreign key e viceversa per “lazy=false”.

Inoltre, la classe Corso ha una relazione n->m con la classe Soggetto (nel ruolo di discenti o allievi). Infatti, concettualmente un
corso ha n discenti mentre, viceversa, un discente può seguire m corsi.

In Java la suddetta relazione n->m è definita tramite un attributo di tipo Set (o comunque Collection) di tipo Soggetto nella classe
Corso e tramite un attributo Set di tipo Corso nella classe Soggetto.

Ovvero, nella classe Corso avremo:

private Set<Soggetto> discenti = null;

e nella classe Soggetto avremo:

12
private Set<Corso> corsi = null;

Lato database questo tipo di relazione si traduce nella creazione di una nuova tabella, detta associativa, tra le tabella Corso e
Soggetto.

Lato Hibernate la relazione si mappa in entrambi i file Corso.hbm.xml e Soggetto.hbm.xml.

In Corso.hbm.xml avremo:

<set name="discenti" table="corsi_partecipanti" lazy="false">


<key column="corsoId"/>
<many-to-many column="partecipanteId" class="com.azienda.progettoCorso.model.Soggetto"/>
</set>

Mentre in Soggetto.hbm.xml avremo:

<set name="corsi" table="corsi_partecipanti" lazy="false">


<key column="partecipanteId"/>
<many-to-many column="corsoId" class="com.azienda.progettoCorso.model.Corso"/>
</set>

Dall’analisi delle relazioni n->1 ed n->m che abbiamo appena mostrato notiamo subito un grande vantaggio per il
programmatore Java relativo all’uso di Hibernate:

13
il programmatore Java non si dovrà preoccupare di scrivere le istruzioni SQL di creazione delle tabelle, delle foreign key e
persino della creazione della tabella associativa nel caso delle relazioni n->m. Tutto il lavoro appena menzionato sarà
automaticamente svolto da Hibernate. L’unico compito del programmatore Java è la definzione dei file xml di mapping visti
prima.

Configurazione di Hibernate

La configurazione principale di Hibernate in cui, tra le altre cose, vengono specificati i parametri di accesso al database ed i
puntamenti ai singoli file di mapping tra le classi Java e le tabelle di database, viene effettuata all’interno del file
hibernate.cfg.xml.

Vediamo subito un esempio relativo al nostro progetto “Corso”:

<?xml version='1.0' encoding='utf-8'?>


<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">org.postgresql.Driver</property>
<property name="connection.url">jdbc:postgresql://localhost:5433/corso</property>
<property name="connection.username">corso</property>
<property name="connection.password">corso</property>
<!-- JDBC connection pool (use the built-in) -->

14
<property name="connection.pool_size">1</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">update</property>
<mapping resource="com/azienda/progettoCorso/model/hbm/Materia.hbm.xml"/>
<mapping resource="com/azienda/progettoCorso/model/hbm/Aula.hbm.xml"/>
<mapping resource="com/azienda/progettoCorso/model/hbm/Sede.hbm.xml"/>
<mapping resource="com/azienda/progettoCorso/model/hbm/Soggetto.hbm.xml"/>
<mapping resource="com/azienda/progettoCorso/model/hbm/Corso.hbm.xml"/>
<mapping resource="com/azienda/progettoCorso/model/hbm/Utente.hbm.xml"/>
</session-factory>
</hibernate-configuration>

I parametri di connessione al database sono definiti nelle property:

<property name="connection.driver_class">org.postgresql.Driver</property>
<property name="connection.url">jdbc:postgresql://localhost:5433/corso</property>
<property name="connection.username">corso</property>
<property name="connection.password">corso</property>

15
La property di nome dialect serve ad istruire Hibernate sul tipo di R-DBMS che si sta utilizzando. Questo è necessario in quanto
ogni singolo R-DBMS (purtroppo) può introdurre delle istruzioni SQL personalizzate che si discostano dallo standard SQL.
Questa personalizzazione dell’SQL da parte degli R-DBMS in gergo viene chiamata “dialetto”.

Anche per il valore della stringa da usare per il dialect, così come abbiamo già visto per la stringa che identifica il tipo di driver
Jdbc, l’url di connessione al database, occorre controllare la documentazione dello specifico R-DBMS utilizzato. Noi, utilizzando
PostgreSql, in tutto il corso abbiamo riportato i valori delle stringhe relativi appunto a PostgreSql, ma occorre essere a
conoscenza del fatto che cambiando R-DBMS i valori di queste stringhe cambieranno.

La property <property name="hbm2ddl.auto">update</property> indica il tipo di operazione che Hibernate deve effettuare
sulle tabelle del database all’avvio. Il valore update, che rappresenta la best-practice, istruisce Hibernate di creare le tabelle se
non esistono già, viceversa se le tabelle già esistono Hibernate dovrà controllare se ci sono stati aggiornamenti nei file di mapping
(ad esempio l’aggiunta o la rimozione di un campo di una tabella) ed in caso affermativo provvedere ad effettuare i relativi
aggiornamenti alle tabelle del database. Questa è, quindi, la property che permette di creare/aggiornare le tabelle del database
direttamente a partire dai file xml di mapping.

Un altro valore possibile per questa property è create che istruisce Hibernate di ricreare sempre da zero le tabelle del database.
Ovviamente, in un ambiente reale di esercizio è assolutamente da evitare l’opzione create altrimenti le tabelle verrebbero
cancellate e ricreate ad ogni riavvio di Hibernate.

16
A questo punto guardiamo il codice necessario per avviare Hibernate. Essenzialmente, quello che occorre fare per avviare
Hibernate è:

• informare Hibernare sul path in cui è presente il file principale di configurazione, hibernate.cfg.xml

• creare una sessione Hibernate

• aprire una transazione (in Hibernate il default è in auto-commit=false)

• lanciare istruzione SQL

• chiudere la transazione con un commit o con un rollback

• chiudere la sessione Hibernate

Ecco un esempio del codice di inizializzazione di Hibernate:

Configuration configuration = new Configuration();


configuration.configure("/com/azienda/progettoCorso/model/hbm/hibernate.cfg.xml");
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();

Transaction transaction = session.beginTransaction();


//…istruzioni SQL
transaction.commmit();
session.getSessionFactory().close();

17
Vediamo adesso come inviare istruzioni SQL al R-DBMS tramite Hibernate.

Insert

La classe Session di Hibernate espone un metodo save(Object object) che effettua l’inserimento dell’oggetto object che gli viene
passato come parametro di ingresso nel database e restituisce l’identificativo dell’oggetto inserito.

Ad esempio , per salvare un oggetto di classe Materia:

MateriaId materiaSaved = (MateriaId) session.save(materia);


return materiaSaved;

Nell’esempio abbiamo passato al metodo save un oggetto materia di classe Materia ed abbiamo effettuato il cast dell’oggetto
restituito dal metodo a MateriaId (classe-wrapper intorno all’identificativo della classe Materia).

L’esempio mostra chiaramente il concetto che abbiamo precedentemente illustrato riguardo la capacità di un tool ORM, come
Hibernate, di lanciare istruzioni SQL senza dover utilizzare direttamente la sintassi SQL. Notiamo l’estrema semplicità
dell’istruzione, soprattutto se confrontata con l’equivalente in Jdbc. Infatti, se avessimo voluto inserire l’oggetto materia su
database in Jdbc, avremmo dovuto leggere i singoli attributi dell’oggetto materia, creare un’istanza di Statement, creare una
stringa del tipo “insert into Materia values(“ + materia.getNome()……

18
In Hibernate è sufficiente richiamare session.save() e l’INSERT SQL è completa. Ovviamente, come già detto, previa
configurazione del mapping tra classe Java e tabella del database nel file xml.

Update

Analogamente all’inserimento, per l’aggiornamento è sufficiente chiamare semplicemente il metodo update:

session.update(materia)

L’unica attenzione da porre è che l’oggetto passato come parametro di ingresso al metodo update, nel nostro esempio materia,
deve essere già presente sul database. Inoltre l’effetto dell’update (se è verificata la condizione precedente) è che tutti gli attributi
presenti nell’oggetto andranno a sovrascrivere i vecchi valori dei campi su database.

Nel nostro esempio, se l’oggetto materia avesse valorizzati gli attributi nome=”JAVA” e descrizione=”Corso Java”, perché
l’update abbia effetto deve esistere un record nella tabella Materia con primary key nome=”JAVA”.

Notiamo anche che se materia avesse l’attributo descrizione=null l’effetto dell’update sarebbe quello di annullare il relativo
campo descrizione su database.

Delete

Anche la cancellazione viene effettuata attraverso un’unica chiamata al metodo delete della classe Session:

19
session.delete(materia);

Il metodo delete affinchè abbia effetto deve esistere su database la chiave primaria corrispondente all’identificativo dell’oggetto
materia, nel nostro caso il campo nome.

Query

Hibernate mette a disposizione diversi modi per effettuare query su database. I principali sono

• Query By Criteria

• Hql (Hibernate Query Language)

• Query Native

In questo corso ci concentreremo sulle query by Criteria che sono le più simili al modo di ragionare “Object Oriented”.

Hql è una sorta di ibrido tra query SQL in stile Jdbc e uno stile puramente ad oggetti, mentre le query native permettono di
lanciare tramite Hibernate query in pieno stile SQL.

20
Query by Criteria

Un oggetto di classe Criteria può essere visto come la versione ad oggetti della clausola SELECT …FROM tabella in SQL.

Un’istanza di Criteria viene infatti costruita a partire dall’oggetto Session fornendo il nome della classe Java corrispondente alla
tabella del db su cui vogliamo lanciare query.

Ad esempio:

Criteria criteria = session.createCriteria(Materia.class);

potremmo anche già mandare in esecuzione la query invocando l’istruzione criteria.list(). In questo caso staremmo lanciando
l’equivalente di SELECT * FROM Materia.

Il risultato del metodo list() restituisce una lista di oggetti, nel nostro caso di classe Materia:

List<Materia> result = criteria.list();

Se vogliamo aggiungere delle condizioni di filtro nella query, ovvero l’equivalente SQL della clausola WHERE campo1=valore1
AND campo2=valore2 possiamo aggiungere all’oggetto criteria delle istanze della classe Criterion.

I tipi di Criterion più diffusi sono senz’altro le istanze di Restrictions.

21
Ad esempio per aggiungere alla nostra istanza criteria una where conditions su descrizione=”valore” dovremmo scrivere:

String s = ”valore”;

criteria.add(Restrictions.eq(“descrizione”,s));

L’istruzione appena mostrata è l’equivalente di SELECT * FROM Materia WHERE descrizione=’valore’.

Il metodo eq di Restrictions riceve come parametro di ingresso il nome dell’attributo su cui vogliamo impostare la where
condition così com’è scritto nel file di mapping, e il valore da usare come filtro.

In SQL quando le where conditions sono applicate su campi di tipo stringa è possibile anche usare la clausola LIKE:

SELECT * FROM Materia WHERE descrizione LIKE ‘%val%’

che equivale a ricercare tutti i record della tabella Materia con valore del campo descrizione che contenga la stringa “val”.

Nella stringa dopo la clausola LIKE è possibile usare il carattere % prima, dopo o sia prima che dopo la stringa:

• %val equivale a cercare tutte le stringhe che hanno qualsiasi carattere prima di val

• val% equivale a cercare tutte le stringhe che hanno qualsiasi carattere dopo la stringa val

• %val% equivale a cercare tutte le stringhe che hanno qualsiasi carattere prima e qualsiasi carattere dopo val

22
In Hibernate l’equivalente della LIKE si ottiene utilizzando il metodo ilike, dove la i iniziale sta per “ignore-case”, quindi senza
distinguere nemmeno tra lettere maiuscole e minuscole:

criteria.add(Restrictions.ilike(“descrizione”,”val”,MatchMode.ANYWHERE));

l’ultimo parametro serve ad indicare il carattere % dove va posizionato nell’equivalente query SQL:

• MatchMode.ANYWHERE equivale a posizionare % sia prima che dopo

• MatchMode.START equivale a posizionare % solo prima

• MatchMode.END equivale a posizionare % solo dopo

Quindi l’istruzione Hibernate:

criteria.add(Restrictions.ilike("descrizione",materia.getDescrizione(),MatchMode.ANYWHERE));

equivale in SQL a:

WHERE descrizione LIKE ‘%valore%’

Ribadiamo che la clausola LIKE è applicabile solo quando il campo è di tipo stringa.

23
Occorre, infatti, sempre prestare attenzione al tipo di dato: se ad esempio stiamo aggiungendo una Restrictions su di un campo di
tipo Integer non possiamo utilizzare il metodo ilike, dovremo per esempio utilizzare il metodo eq ed, inoltre, secondo parametro
del metodo eq, che rappresenta il valore, deve essere di tipo Integer.

Ad esempio, nel nostro progetto “Corso” abbiamo definito per la classe Corso l’attributo numeroSessioni di tipo Integer:

private Integer numeroSessioni = null;

e, conseguentemente nel file di mapping Corso.hbm.xml abbiamo inserito:

<property name="numeroSessioni" type="java.lang.Integer">


<column name="numeroSessioni" precision="9" scale="0"/>
</property>

Se volessimo scrivere in Hibernate l’equivalente della query SQL:

SELECT * FROM CorsoWHERE numeroSessioni=20;

dovremo scrivere il seguente codice Java:

Integer i = new Integer(20);

Criteria criteria = session.createCriteria(Corso.class);

24
criteria.add(Restrictions.eq(“numeroSessioni”,i));

List<Corso> result = criteria.list();

Se provassimo a scorrere i risultati della query appena mostrata potremmo riscontrare il concetto della inizializzazione lazy che
abbiamo menzionato precedentemente.

Se guardiamo la seguente sezione del file di mapping Corso.hbm.xml:

<many-to-one name="materia" class="com.azienda.progettoCorso.model.Materia" column="materia" lazy="false"/>

la property lazy=”false” determina che ogni singolo oggetto di classe Corso contenuto nella lista result sarà già popolato da
Hibernate con l’attributo materia di classe Materia.

Se invece nel file di mapping avessimo impostato lazy=”true”, ogni singolo oggetto di classe Corso contenuto nella lista result
avrebbe avuto inizialmente l’attributo materia non popolato. Al momento di una eventuale chiamata esplicita al metodo
corso.getMateria() Hibernate avrebbe rieseguito la query sul database per popolare l’attributo materia dell’oggetto corso.

25