I\'ve have already implemented pagination using the following code:
public Paginacao consultarPaginado(int pagina, Integer cidadeId) {
After a long time looking for a solution for my problem I managed to solve it. The problem that if you create a criteria or query that retrieves toMany associations using JOINS, and then you use setMaxResults and set the ResultTransformer to DISTINCT_ROOT_ENTITY the result won't be as you expected.
As JB Nizet said, suppose you have 4 A entities, each with 3 B entities, and suppose your query retrieves all the A entities with their Bs.
In that case, the SQL query will return 12 rows. If you use setMaxResults(7), it will retrieve (for example) three rows for A1 and its Bs, three rows for A2 and its Bs, and just 1 row for A3 and its first B.
And since you have used DISTINCT_ROOT_ENTITY, the criteria query will return only three entities: A1, A2, and A3 (which will have an incomplete set of Bs).
To solve this, you have to set the FETCH MODE for toMany (usually collections) relationships to SELECT or SUBSELECT, and you have basically 2 ways to achieve this:
The first way is to use @FetchMode(FetchMode.SUBSELECT) annotation on your attribute, and I don't like this approach because it causes every query to use SUBSELECT FETCH to retrieve the collection. But it will work.
The other way is to set fetch modes for relationships when you build your query. I prefer this way, because I can customize the query to my needs and I don't have to use SUBSELECTS to all queries. So, I've done this way:
public Paginacao consultarPaginado(int pagina, Integer cidadeId) {
Criteria criteria = this.sessionFactory.getCurrentSession().createCriteria(Anuncio.class);
criteria.add(Restrictions.eq("ativo", true));
criteria.add(Restrictions.eq("statusLiberacao", AnunciosUtil.STATUS_ANUNCIO_LIBERADO));
criteria.add(Restrictions.eq("statusVendaAnuncio", AnunciosUtil.STATUS_VENDA_ANUNCIO_DISPONIVEL));
criteria.setFetchMode("imagens", FetchMode.SELECT);
criteria.setFetchMode("pagamentos", FetchMode.SELECT);
if (cidadeId != null) {
criteria.add(Restrictions.eq("cidade.id", cidadeId));
}
criteria.addOrder(Order.desc("dataPostagem"));
criteria.setProjection(Projections.rowCount());
Long count = (Long) criteria.uniqueResult();
Paginacao paginacao = new Paginacao();
int qtdPaginas = (count.intValue() / 7) + 1;
paginacao.setQtdPaginas(qtdPaginas);
criteria.setProjection(null);// reseta a criteria sem a projeção
criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
if (pagina > qtdPaginas) {
pagina = qtdPaginas;
}
pagina = pagina - 1;
criteria.setFirstResult(pagina * ConstantesGenericas.MAXIMO_OBJETOS_RETORNADOS);
criteria.setMaxResults(ConstantesGenericas.MAXIMO_OBJETOS_RETORNADOS);
paginacao.setRegistros(criteria.list());
return paginacao;
}
Hope that it helps anyone else. ;D