Capitolo 12. Interrogazioni per criteri

Hibernate ora offre una API di interrogazione per criteri intuitiva ed estensibile. Per ora quest'API è meno potente delle più mature funzionalità di interrogazione HQL. In particolare, le interrogazioni per criteri non supportano la proiezione o l'aggregazione.

12.1. Creazione di un'istanza di Criteria

L'interfaccia net.sf.hibernate.Criteria rappresenta un'interrogazione nei confronti di una particolare classe persistente. La Session è un produttore di istanze di Criteria.

Criteria crit = sess.createCriteria(Cat.class);
crit.setMaxResults(50);
List cats = crit.list();

12.2. Riduzione dell'insieme dei risultati

Un criterio individuale di interrogazione è un'istanza dell'interfaccia net.sf.hibernate.expression.Criterion. La classe net.sf.hibernate.expression.Expression definisce metodi "factory" (produttori) per otteere alcuni tipi predefiniti di Criterion.

List cats = sess.createCriteria(Cat.class)
    .add( Expression.like("name", "Fritz%") )
    .add( Expression.between("weight", minWeight, maxWeight) )
    .list();

Le espressioni possono essere raggruppate logicamente.

List cats = sess.createCriteria(Cat.class)
    .add( Expression.like("name", "Fritz%") )
    .add( Expression.or(
        Expression.eq( "age", new Integer(0) ),
        Expression.isNull("age")
    ) )
    .list();
List cats = sess.createCriteria(Cat.class)
    .add( Expression.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )
    .add( Expression.disjunction()
        .add( Expression.isNull("age") )
    	.add( Expression.eq("age", new Integer(0) ) )
    	.add( Expression.eq("age", new Integer(1) ) )
    	.add( Expression.eq("age", new Integer(2) ) )
    ) )
    .list();

C'è un certo numero di tipi di criterio predefiniti (sottoclassi di Expression ), ma uno di essi è particolarmente utile, perché consente di specificare direttamente dell'SQL.

List cats = sess.createCriteria(Cat.class)
    .add( Expression.sql("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRING) )
    .list();

il segnaposto {alias} verrà sostituito dall'alias di riga della entità su cui si sta facendo l'interrogazione.

12.3. Ordinamento dei risultati

È possibile ordinare i risultati utilizzando net.sf.hibernate.expression.Order.

List cats = sess.createCriteria(Cat.class)
    .add( Expression.like("name", "F%")
    .addOrder( Order.asc("name") )
    .addOrder( Order.desc("age") )
    .setMaxResults(50)
    .list();

12.4. Associazioni

Potete specificare semplicemente vincoli su entità correlate navigando le associazioni utilizzando createCriteria().

List cats = sess.createCriteria(Cat.class)
    .add( Expression.like("name", "F%")
    .createCriteria("kittens")
        .add( Expression.like("name", "F%")
    .list();

notate che il secondo createCriteria() restituisce una nuova istanza di Criteria che si riferisce agli elementi della collezione kittens.

La forma alternativa seguente è utile in alcune circostanze.

List cats = sess.createCriteria(Cat.class)
    .createAlias("kittens", "kt")
    .createAlias("mate", "mt")
    .add( Expression.eqProperty("kt.name", "mt.name") )
    .list();

(createAlias() non crea una nuova istanza di Criteria.)

Notate che le collezioni kittens che appartengono alle istanze di Cat restituita dalle due interrogazioni precedenti non sono pre-filtrate dal criterio! Se volete recuperare solo i gattini che corrispondano al criterio, dovete utilizzare returnMaps().

List cats = sess.createCriteria(Cat.class)
    .createCriteria("kittens", "kt")
        .add( Expression.eq("name", "F%") )
    .returnMaps()
    .list();
Iterator iter = cats.iterator();
while ( iter.hasNext() ) {
    Map map = (Map) iter.next();
    Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS);
    Cat kitten = (Cat) map.get("kt");
}

12.5. Caricamento dinamico delle associazioni

Usando il metodo setFetchMode() è possibile specificare la semantica di caricamento delle associazioni in fase di esecuzione.

List cats = sess.createCriteria(Cat.class)
    .add( Expression.like("name", "Fritz%") )
    .setFetchMode("mate", FetchMode.EAGER)
    .setFetchMode("kittens", FetchMode.EAGER)
    .list();

Questa interrogazione caricher sia mate sia kittens tramite join esterni.

12.6. Interrogazioni per esempi

La classe net.sf.hibernate.expression.Example permette di costruire un criterio di interrogazione a partire da una data istanza.

Cat cat = new Cat();
cat.setSex('F');
cat.setColor(Color.BLACK);
List results = session.createCriteria(Cat.class)
    .add( Example.create(cat) )
    .list();

Le proprietà di versione, gli identificatori e le associazioni vengono ignorati. Il comportamento predefinito è di escludere le proprietà di valore null.

Potete impostare come l'Example venga applicato.

Example example = Example.create(cat)
    .excludeZeroes()           //exclude zero valued properties
    .excludeProperty("color")  //exclude the property named "color"
    .ignoreCase()              //perform case insensitive string comparisons
    .enableLike();             //use like for string comparisons
List results = session.createCriteria(Cat.class)
    .add(example)
    .list();

Potete anche usare gli esempi per impostare criteri sugli oggetti associati.

List results = session.createCriteria(Cat.class)
    .add( Example.create(cat) )
    .createCriteria("mate")
        .add( Example.create( cat.getMate() ) )
    .list();