Classificando com o Hibernate
1. Visão geral
Este artigo ilustrahow to Sort with Hibernate, usando a linguagem de consulta Hibernate (HQL) e a API de critérios.
Leitura adicional:
Hibernate: salvar, persistir, atualizar, mesclar, saveOrUpdate
Um guia rápido e prático para os métodos de gravação do Hibernate: salvar, persistir, atualizar, mesclar, saveOrUpdate.
Interceptores de hibernação
Um guia rápido e prático para criar interceptores do Hibernate.
2. Classificação com HQL
Classificar com HQL do Hibernate é tão simples quanto adicionar a cláusulaOrder By à string de consulta HQL:
String hql = "FROM Foo f ORDER BY f.name";
Query query = sess.createQuery(hql);
Após a execução desse código, o Hibernate gerará a seguinte consulta SQL:
Hibernate: select foo0_.ID as ID1_0_, foo0_.NAME as NAME2_0_ from
FOO foo0_ order by foo0_.NAME
A direção padrão da ordem de classificação é crescente. É por isso que a condição de pedidoasc não está incluída na consulta SQL gerada.
2.1. Usando uma ordem de classificação explícita
Para especificar a ordem de classificação manualmente - você precisará incluir a direção do pedido na string de consultaHQL:
String hql = "FROM Foo f ORDER BY f.name ASC";
Query query = sess.createQuery(hql);
Neste exemplo, a configuração da cláusulaasc no HQL foi incluída na consulta SQL gerada:
Hibernate: select foo0_.ID as ID1_0_, foo0_.NAME as NAME2_0_
from FOO foo0_ order by foo0_.NAME ASC
2.2. Classificando por mais de um atributo
Vários atributos, junto com uma ordem de classificação opcional, podem ser adicionados à cláusulaOrder By na string de consulta HQL:
String hql = "FROM Foo f ORDER BY f.name DESC, f.id ASC";
Query query = sess.createQuery(hql);
A consulta SQL gerada será alterada de acordo:
Hibernate: select foo0_.ID as ID1_0_, foo0_.NAME as NAME2_0_
from FOO foo0_ order by foo0_.NAME DESC, foo0_.ID ASC
2.3. Definir a precedência de classificação de valores nulos
Por padrão, quando o atributo a ser classificado tem valores denull, cabe ao RDMS decidir a precedência. Este tratamento padrão pode ser substituído colocandoa NULLS FIRST or NULLS LAST clause in the HQL query string.
Este exemplo simples coloca quaisquer valores nulos no final da lista de resultados:
String hql = "FROM Foo f ORDER BY f.name NULLS LAST";
Query query = sess.createQuery(hql);
Vamos ver a cláusulais null then 1 else 0 emgenerated SQL query:
Hibernate: select foo0_.ID as ID1_1_, foo0_.NAME as NAME2_1_,
foo0_.BAR_ID as BAR_ID3_1_, foo0_.idx as idx4_1_ from FOO foo0_
order by case when foo0_.NAME is null then 1 else 0 end, foo0_.NAME
2.4. Classificando relações um para muitos
Vamos analisar um caso de classificação complexo:sorting entities in a one to many relation -Bar contendo uma coleção de entidadesFoo.
Faremos isso anotando a coleção comthe Hibernate @OrderBy annotation; iremos especificar o campo pelo qual o pedido é feito, bem como a direção:
@OrderBy(clause = "NAME DESC")
Set fooList = new HashSet();
Observe que o argumentoclause para a anotação. Isso é exclusivo para@OrderBy do Hibernate, em comparação com a anotação JPA@OrderBy semelhante. Outra característica que diferencia esta abordagem de seu equivalente JPA é que o argumentoclause indica que a classificação é feita com base na colunaNAME da tabelaFOO, não nanameatributo s deFoo.
Agora, vamos dar uma olhada na classificação real deBarseFoos:
String hql = "FROM Bar b ORDER BY b.id";
Query query = sess.createQuery(hql);
Oresulting SQL statement mostra que osFoo’s classificados são colocados em umfooList:
Hibernate: select bar0_.ID as ID1_0_, bar0_.NAME as NAME2_0_ from BAR bar0_
order by bar0_.ID Hibernate: select foolist0_.BAR_ID as BAR_ID3_0_0_,
foolist0_.ID as ID1_1_0_, foolist0_.ID as ID1_1_1_, foolist0_.NAME as
NAME2_1_1_, foolist0_.BAR_ID as BAR_ID3_1_1_, foolist0_.idx as idx4_1_1_
from FOO foolist0_ where foolist0_.BAR_ID=? order by foolist0_.NAME desc
Uma coisa a ter em mente é que énot possible to to sort Lists como era o caso com JPA. A documentação do Hibernate indica:
“O Hibernate atualmente ignora @OrderBy em @ElementCollection em, por exemplo Lista <>. A ordem dos elementos é a retornada pelo banco de dados, indefinida. ”
Como uma observação lateral, seria possível contornar essa limitação usando a configuração XML legada para Hibernate e substituindo o elemento<List..> por um elemento<Bag…>.
3. Classificação com critérios de hibernação
A API Criteria Object fornece a classeOrder como a API principal para gerenciar a classificação.
3.1. Definir a ordem de classificação
A classeOrder tem dois métodos para definir a ordem de classificação:
-
*asc*(String attribute): Classifica a consulta porattribute em ordem crescente.
-
*desc*(String attribute): classifica a consulta porattribute em ordem decrescente.
Vamos começar com um exemplo simples - classificando por um único atributoid:
Criteria criteria = sess.createCriteria(Foo.class, "FOO");
criteria.addOrder(Order.asc("id"));
Observe que o argumento para o métodoasc diferencia maiúsculas de minúsculas e deve corresponder aoname do atributo pelo qual classificar.
A API Object do Hibernate Criteria define explicitamente uma direção de ordem de classificação e isso é refletido na instrução SQL gerada pelo código:
Hibernate: select this_.ID as ID1_0_0_, this_.NAME as NAME2_0_0_
from FOO this_ order by this_.ID sac
3.2. Classificando por mais de um atributo
A classificação por vários atributos requer apenas a adição de um objetoOrder à instânciaCriteria, como no exemplo abaixo:
Criteria criteria = sess.createCriteria(Foo.class, "FOO");
criteria.addOrder(Order.asc("name"));
criteria.addOrder(Order.asc("id"));
A consulta gerada no SQL é:
Hibernate: select this_.ID as ID1_0_0_, this_.NAME as NAME2_0_0_ from
FOO this_ order by this_.NAME asc, this_.ID sac
3.3. Definir a precedência de classificação de valores nulos
Por padrão, quando o atributo a ser classificado tem valores denull, cabe ao RDMS decidir a precedência. A API de objetos de critérios do Hibernate torna simples alterar esse padrão eplace nulls at the end de uma lista ordenada crescente:
Criteria criteria = sess.createCriteria(Foo.class, "FOO");
criteria.addOrder(Order.asc("name").nulls(NullPrecedence.LAST));
Aqui está a consultaSQL subjacente - com a cláusulais null then 1 else 0:
Hibernate: select this_.ID as ID1_1_1_, this_.NAME as NAME2_1_1_,
this_.BAR_ID as BAR_ID3_1_1_, this_.idx as idx4_1_1_, bar2_.ID as
ID1_0_0_, bar2_.NAME as NAME2_0_0_ from FOO order by case when
this_.NAME is null then 1 else 0 end, this_.NAME asc
Como alternativa, também podemosplace the nulls at the beginning de uma lista ordenada decrescente:
Criteria criteria = sess.createCriteria(Foo.class, "FOO");
criteria.addOrder(Order.desc("name").nulls(NullPrecedence.FIRST));
A consulta SQL correspondente segue - com a cláusulais null then 0 else 1:
Hibernate: select this_.ID as ID1_1_1_, this_.NAME as NAME2_1_1_,
this_.BAR_ID as BAR_ID3_1_1_, this_.idx as idx4_1_1_, bar2_.ID as
ID1_0_0_, bar2_.NAME as NAME2_0_0_ from FOO order by case when
this_.NAME is null then 0 else 1 end, this_.NAME desc
Observe que,if the attribute to sort by is a primitive type like an int, a PresisitenceException will thrown.
Por exemplo, se o valor def.anIntVariable for nulo, a execução da consulta:
String jql = "Select f from Foo as f order by f.anIntVariable desc NULLS FIRST";
Query sortQuery = entityManager.createQuery(jql);
jogará:
javax.persistence.PersistenceException: org.hibernate.PropertyAccessException:
Null value was assigned to a property of primitive type setter of
com.cc.jpa.example.Foo.anIntVariable
4. Conclusão
Este artigo explora a classificação com o Hibernate - usando as APIs disponíveis para entidades simples e também para entidades em uma relação de um para muitos.
A implementação deste tutorial de classificação do Hibernate pode ser encontrada emthe github project - este é um projeto baseado em Eclipse, portanto, deve ser fácil de importar e executar como está.