Hibernate.orgCommunity Documentation
O Hibernate provê uma API de consulta por critério intuitiva e extensível.
A interface org.hibernate.Criteria
representa a consulta ao invés de uma classe persistente particular. A sessão é uma fábrica para instâncias de Criteria
.
Criteria crit = sess.createCriteria(Cat.class);
crit.setMaxResults(50);
List cats = crit.list();
Um critério individual de consulta é uma instância da interface org.hibernate.criterion.Criterion
. A classe org.hibernate.criterion.Restrictions
define os métodos da fábrica para obter certos tipos de Criterion
pré fabricados.
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.add( Restrictions.between("weight", minWeight, maxWeight) )
.list();
Restrições podem ser logicamente agrupadas.
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.add( Restrictions.or(
Restrictions.eq( "age", new Integer(0) ),
Restrictions.isNull("age")
) )
.list();
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )
.add( Restrictions.disjunction()
.add( Restrictions.isNull("age") )
.add( Restrictions.eq("age", new Integer(0) ) )
.add( Restrictions.eq("age", new Integer(1) ) )
.add( Restrictions.eq("age", new Integer(2) ) )
) )
.list();
Existe um grande número de critérios pré-fabricados (subclasses de Restrictions
). Um dos mais úteis permite especificar o SQL diretamente.
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.sqlRestriction("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRING) )
.list();
O parâmetro {alias}
será substituido pelo alias da entidade procurada.
Uma maneira alternativa de obter um critério é apartir de uma instância Property
. Você pode criar uma Property
chamando Property.forName()
:
Property age = Property.forName("age");
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.disjunction()
.add( age.isNull() )
.add( age.eq( new Integer(0) ) )
.add( age.eq( new Integer(1) ) )
.add( age.eq( new Integer(2) ) )
) )
.add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) )
.list();
Você poderá ordenar os resultados usando org.hibernate.criterion.Order
.
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "F%")
.addOrder( Order.asc("name") )
.addOrder( Order.desc("age") )
.setMaxResults(50)
.list();
List cats = sess.createCriteria(Cat.class)
.add( Property.forName("name").like("F%") )
.addOrder( Property.forName("name").asc() )
.addOrder( Property.forName("age").desc() )
.setMaxResults(50)
.list();
Através da navegação de associações usando createCriteria()
, você pode especificar restrições por entidades relacionadas:
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "F%") )
.createCriteria("kittens")
.add( Restrictions.like("name", "F%") )
.list();
Note que o segundo createCriteria()
retorna uma nova instância de Criteria
, que refere aos elementos da coleção kittens
.
A seguinte forma alternada é útil em certas circunstâncias:
List cats = sess.createCriteria(Cat.class)
.createAlias("kittens", "kt")
.createAlias("mate", "mt")
.add( Restrictions.eqProperty("kt.name", "mt.name") )
.list();
(createAlias()
não cria uma nova instância de Criteria
.)
Note que as coleções de kittens mantidas pelas instâncias Cat
, retornadas pelas duas consultas anteriores não são pré-filtradas pelo critério. Se você desejar recuperar somente os kittens que se encaixarem ao critérios, você deverá usar um ResultTransformer
.
List cats = sess.createCriteria(Cat.class)
.createCriteria("kittens", "kt")
.add( Restrictions.eq("name", "F%") )
.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
.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");
}
Você pode ainda manipular o conjunto do resultado usando a junção exterior restante:
List cats = session.createCriteria( Cat.class ) .createAlias("mate", "mt", Criteria.LEFT_JOIN, Restrictions.like("mt.name", "good%") ) .addOrder(Order.asc("mt.age")) .list();
Isto retornará todos os Cat
s com um mate (amigo) cujo nome inicia com "bom" ordenado pela idade de seu mate e todos os cats que não tem mates. Isto é útil quando houver necessidade de pedir ou limitar a prioridade do banco de dados em retornar conjuntos de resultado complexo/grande e remover muitas instâncias onde consultas múltiplas deveriam ter sido executadas e os resultados unidos pelo java em memória.
Sem este recurso, o primeiro de todos os cats sem um mate teria que ser carregado em uma consulta.
Uma segunda consulta teria que restaurar os cats com os mates cujos os nomes iniciem com "bom" selecionados pelas idades dos mates.
A terceira, em memória; as listas teriam que ser unidas manualmente.
Você deve especificar as semânticas de busca de associação em tempo de execução usando setFetchMode()
.
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.setFetchMode("mate", FetchMode.EAGER)
.setFetchMode("kittens", FetchMode.EAGER)
.list();
This query will fetch both mate
and kittens
by outer join. See Seção 21.1, “Estratégias de Busca ” for more information.
A classe org.hibernate.criterion.Example
permite que você construa um critério de consulta a partir de uma dada instância.
Cat cat = new Cat();
cat.setSex('F');
cat.setColor(Color.BLACK);
List results = session.createCriteria(Cat.class)
.add( Example.create(cat) )
.list();
Propriedades de versão, identificadores e associações são ignoradas. Por padrão, as propriedades de valor null são excluídas.
Você pode ajustar como o Exemplo
é aplicado.
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();
Você pode até usar os exemplos para colocar os critérios em objetos associados.
List results = session.createCriteria(Cat.class)
.add( Example.create(cat) )
.createCriteria("mate")
.add( Example.create( cat.getMate() ) )
.list();
A classe org.hibernate.criterion.Projections
é uma fábrica para instâncias de Projection
. Você pode aplicar uma projeção à uma consulta, chamando o setProjection()
.
List results = session.createCriteria(Cat.class)
.setProjection( Projections.rowCount() )
.add( Restrictions.eq("color", Color.BLACK) )
.list();
List results = session.createCriteria(Cat.class)
.setProjection( Projections.projectionList()
.add( Projections.rowCount() )
.add( Projections.avg("weight") )
.add( Projections.max("weight") )
.add( Projections.groupProperty("color") )
)
.list();
Não há necessidade de um "agrupamento por" explícito em uma consulta por critério. Certos tipos de projeção são definidos para serem projeções de agrupamento, que também aparecem em uma cláusula agrupamento por
SQL.
Um alias pode ser atribuído de forma opcional à uma projeção, assim o valor projetado pode ser referenciado em restrições ou ordenações. Aqui seguem duas formas diferentes para fazer isto:
List results = session.createCriteria(Cat.class)
.setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) )
.addOrder( Order.asc("colr") )
.list();
List results = session.createCriteria(Cat.class)
.setProjection( Projections.groupProperty("color").as("colr") )
.addOrder( Order.asc("colr") )
.list();
Os métodos alias()
e as()
simplesmente envolvem uma instância de projeção à outra instância de Projeção
em alias. Como um atalho, você poderá atribuir um alias quando adicionar a projeção à uma lista de projeção:
List results = session.createCriteria(Cat.class)
.setProjection( Projections.projectionList()
.add( Projections.rowCount(), "catCountByColor" )
.add( Projections.avg("weight"), "avgWeight" )
.add( Projections.max("weight"), "maxWeight" )
.add( Projections.groupProperty("color"), "color" )
)
.addOrder( Order.desc("catCountByColor") )
.addOrder( Order.desc("avgWeight") )
.list();
List results = session.createCriteria(Domestic.class, "cat")
.createAlias("kittens", "kit")
.setProjection( Projections.projectionList()
.add( Projections.property("cat.name"), "catName" )
.add( Projections.property("kit.name"), "kitName" )
)
.addOrder( Order.asc("catName") )
.addOrder( Order.asc("kitName") )
.list();
Você também pode usar um Property.forName()
para expressar projeções:
List results = session.createCriteria(Cat.class)
.setProjection( Property.forName("name") )
.add( Property.forName("color").eq(Color.BLACK) )
.list();
List results = session.createCriteria(Cat.class)
.setProjection( Projections.projectionList()
.add( Projections.rowCount().as("catCountByColor") )
.add( Property.forName("weight").avg().as("avgWeight") )
.add( Property.forName("weight").max().as("maxWeight") )
.add( Property.forName("color").group().as("color" )
)
.addOrder( Order.desc("catCountByColor") )
.addOrder( Order.desc("avgWeight") )
.list();
A classe DetachedCriteria
deixa você criar uma consulta fora do escopo de uma sessão, e depois executá-la usando alguma Session
arbitrária.
DetachedCriteria query = DetachedCriteria.forClass(Cat.class)
.add( Property.forName("sex").eq('F') );
Session session = ....;
Transaction txn = session.beginTransaction();
List results = query.getExecutableCriteria(session).setMaxResults(100).list();
txn.commit();
session.close();
Um DetachedCriteria
também pode ser usado para expressar uma subconsulta. As instâncias de critérios, que envolvem subconsultas, podem ser obtidas através das Subqueries
ou Property
.
DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)
.setProjection( Property.forName("weight").avg() );
session.createCriteria(Cat.class)
.add( Property.forName("weight").gt(avgWeight) )
.list();
DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)
.setProjection( Property.forName("weight") );
session.createCriteria(Cat.class)
.add( Subqueries.geAll("weight", weights) )
.list();
Até mesmo as subconsultas correlacionadas são possíveis:
DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2")
.setProjection( Property.forName("weight").avg() )
.add( Property.forName("cat2.sex").eqProperty("cat.sex") );
session.createCriteria(Cat.class, "cat")
.add( Property.forName("weight").gt(avgWeightForSex) )
.list();
Para a maioria das consultas, incluindo consultas de critérios, o cache de consulta não é muito eficiente, pois a invalidação do cache de consulta ocorre com muita frequência. No entanto, não há um tipo de consulta especial onde possamos otimizar um algoritmo de invalidação de cache: consultas realizadas por chaves naturais constantes. Em algumas aplicações, este tipo de consulta ocorre com freqüência. O API de critério provê provisão especial para este caso de uso.
Primeiro, você deve mapear a chave natural de sua entidade usando um <natural-id>
e habilitar o uso de um cache de segundo nível.
<class name="User">
<cache usage="read-write"/>
<id name="id">
<generator class="increment"/>
</id>
<natural-id>
<property name="name"/>
<property name="org"/>
</natural-id>
<property name="password"/>
</class
>
Note que esta funcionalidade não é proposta para o uso com entidades com chaves naturais mutáveis.
Uma vez que você tenha ativado o cache de consulta Hibernate, o Restrictions.naturalId()
nos permite que utilizemos um algoritmo de cache mais eficiente.
session.createCriteria(User.class)
.add( Restrictions.naturalId()
.set("name", "gavin")
.set("org", "hb")
).setCacheable(true)
.uniqueResult();
Copyright © 2004 Red Hat, Inc.