9 - Consultes
Hem vist com podem accedir molt còmodament a les classes que equivalen a una taula. Però en moltes ocasions ens farà falta accedir no exactament a una taula sinó a una combinació de taules, o en definitiva voldrem informació més elaborada. Per a poder "interrogar" a la Base de Dades amb consultes més complexes, Hibernate suporta un llenguatge de consulta Orientat a Objectes anomenat HQL (Hibernate Query Language), molt paregut a SQL ja que és una extensió Orientada a Objectes d'aquest.
En aquest sentit s'ha intentat fer un estàndar de llenguatge de consulta anomenat OQL (Object Query Language), desenvolupat per un grup amb ànim de crear un estàndar ODMG (Object Data Management Group). Aquest estàndar no l'ha implementat al 100% cap producte comercial, i en realitat tenim subconjunts d'aquest estàndar.
Utilitzarem la classe Query, i invocarem al mètode createQuery() de Session, que justament torna una Query. Aquest seria un exemple:
Per a recuperar les dades tenim dues possibilitats, utilitzant dos mètodes de la query:
- Mètode list(): torna tots els resultats de la consulta en una col·lecció (List). Aquest mètode fa una crida única al SGBD i es duran totes les dades. Haurà d'haver, per tant, memòria suficient per a que càpiguen tots els resultats. Si és una quantitat gran de resultats, tardarà molt en executar-se.
- Mètode iterate(): torna un iterador per a poder recórrer els resultats de la consulta. Hibernate executa la sentència, però només torna els identificadors de les files del resultat, i cada vegada que fem next() del iterador, s'executa realment la consulta tornant la següent fila. Per tant fa falta molta menys memòria. Per contra es fan mots més accessos a la Base de Dades, encara que cadascun tardarà molt poc, però en total tardarà més. Es pot fins i tot fixar la quantitat de files a tornar amb el mètode setFetchSize().
En el següents dos exemples, que són equivalents, es trau una llista de totes les comarques. El primer utilitza el mètode list() i el segon el mètode iterate(). I en aquesta ocasió utilitzem un iterador per a recórrer la llista (List) en compte de foreach, per veure més d'una manera, i per similitud amb el segon exemple,
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import classes.Comarca;
import classes.SessionFactoryUtil;
public class AccesAmbList {
public static void main(String[] args) {
Session sessio = SessionFactoryUtil.getSessionFactory().openSession();
Query q = sessio.createQuery("from Comarca");
List<Comarca> llista = q.list();
Iterator<Comarca> it = llista.iterator();
while (it.hasNext()) {
Comarca com = it.next();
System.out.println(com.getNomC() + " - " + com.getProvincia());
}
}
}
Aquest serà el resultat

Nota
En cas de no haver incorporat el plugin antlr-3.5.2-complete.jar, necessari per a fer una anàlisi prèvia de la sentència HQL, ens donaria el següent error:

I ho solucionaríem baixant-nos el plugin anterior i incorporant-lo a la nostra llibreria d'Hibernate
Ara amb el mètode iterate():
import org.hibernate.Query;
import org.hibernate.Session;
import classes.Comarca;
import classes.SessionFactoryUtil;
public class AccesAmbIterate {
public static void main(String[] args) {
Session sessio = SessionFactoryUtil.getSessionFactory().openSession();
Query q = sessio.createQuery("from Comarca");
Iterator<Comarca> it = q.iterate();
while (it.hasNext()) {
Comarca com = it.next();
System.out.println(com.getNomC() + " - " + com.getProvincia());
}
}
}
Encara que la manera més curta i potser més clara és utilitzant un bucle foreach amb el mètode list(). Només haurem d'anar amb comte de fer un cast per a que sàpiga quin tipus de llista és:
import org.hibernate.Query;
import org.hibernate.Session;
import classes.Comarca;
import classes.SessionFactoryUtil;
public class AccesAmbListForEach {
public static void main(String[] args) {
Session sessio = SessionFactoryUtil.getSessionFactory().openSession();
Query q = sessio.createQuery("from Comarca");
for (Comarca com : (List<Comarca>) q.list())
System.out.println(com.getNomC() + " - " + com.getProvincia());
}
}
Si sabem que la consulta tornarà únicament una fila, podem assignar aquesta fila a un objecte de la classe de la taula afectada, posant el mètode uniqueResult() en la creació de la query, així ens estaviem passos.
import classes.Comarca;
public class AccesAmbUniqueResult {
public static void main(String[] args) {
Session sessio = SessionFactoryUtil.getSessionFactory().openSession();
Comarca d = (Comarca) sessio.createQuery("from Comarca where nomC='Alcalatén'").uniqueResult();
System.out.println(d.getNomC() + " - " + d.getProvincia());
}
}
Però en realitat en aquest exemple poca cosa hem guanyat, perquè per a agafar l'objecte corresponent a una única fila d'una taula, ja ho féiem amb session.load(). Més endavant veurem consultes més complicades on trobarem la utilitat.
Llicenciat sota la Llicència Creative Commons Reconeixement NoComercial CompartirIgual 2.5