jgu*_*emv 15 hibernate hibernate-criteria
我已经使用以下代码实现了分页:
public Paginacao<Anuncio> 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));
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<Anuncio> paginacao = new Paginacao<Anuncio>();
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;
}
Run Code Online (Sandbox Code Playgroud)
当我手动构建SQL查询并将其提交到数据库时,我得到8个结果.但是,当我尝试上面的代码时,在将ResultTransformer设置为DISTINCT_ROOT_ENTITY之前,获得8个结果(没有区别),并在设置之后得到4个结果.但是我应该得到8个结果(使用DISTINCT),因为当我手动构建SQL而没有不同时,我得到11个结果,当我使用DISTINCT时,我得到了正确的结果.
上面的代码有什么问题?
jgu*_*emv 26
经过很长一段时间寻找我的问题的解决方案,我设法解决了它.如果您创建使用JOINS检索到多个关联的条件或查询,然后使用setMaxResults并将ResultTransformer设置为DISTINCT_ROOT_ENTITY,结果将不是您所期望的问题.
正如JB Nizet所说,假设您有4个A实体,每个实体有3个B实体,并假设您的查询检索所有A实体及其Bs.
在这种情况下,SQL查询将返回12行.如果使用setMaxResults(7),它将为A1及其Bs检索(例如)三行,为A2及其Bs检索三行,为A3及其第一个B检索仅一行.
由于您已使用DISTINCT_ROOT_ENTITY,因此条件查询将仅返回三个实体:A1,A2和A3(将具有不完整的B组).
要解决这个问题,您必须将forCHany(通常是集合)关系的FETCH MODE设置为SELECT或SUBSELECT,并且您基本上有两种方法可以实现此目的:
第一种方法是在属性上使用@FetchMode(FetchMode.SUBSELECT)注释,我不喜欢这种方法,因为它会导致每个查询使用SUBSELECT FETCH来检索集合.但它会奏效.
另一种方法是在构建查询时为关系设置获取模式.我更喜欢这种方式,因为我可以根据自己的需要自定义查询,而不必对所有查询使用SUBSELECTS.所以,我这样做了:
public Paginacao<Anuncio> 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<Anuncio> paginacao = new Paginacao<Anuncio>();
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;
}
Run Code Online (Sandbox Code Playgroud)
希望它能帮助其他人.; d
JB *_*zet 13
我不确定我是否正确理解了您的问题,但是如果您的查询检索到带有toMany关联的实体,则可以按预期分页.
实际上,假设您有4个A实体,每个实体有3个B实体,并假设您的查询检索所有A实体及其Bs.
在这种情况下,SQL查询将返回12行.如果使用setMaxResults(7),它将为A1及其Bs检索(例如)三行,为A2及其Bs检索三行,为A3及其第一个B检索仅一行.
由于您已使用DISTINCT_ROOT_ENTITY,因此条件查询将仅返回三个实体:A1,A2和A3(将具有不完整的B组).
Mat*_*ttC 11
这对我来说是个问题,需要一些时间才能找到适用于我所有场景的解决方案.
每个分页页面你想要的是2件事,所有结果的总数和你的单页结果,但要做到这一点,你需要采取3个步骤.1)获取总计数,2)获取页面的唯一ID,3)获取步骤2中找到的ID的完整数据.您可以使用单个条件对象完成所有这些操作:
1)使用不同的id获取总计数(uniqueField =实体类中id的名称)
Criteria criteria = session.createCriteria(YourEntity.class);
Projection idCountProjection = Projections.countDistinct(uniqueField);
criteria.setProjection(idCountProjection);
//setup criteria, joins etc here
int totalResultCount = ((Long)criteria.uniqueResult()).intValue();
Run Code Online (Sandbox Code Playgroud)
2)重置投影并设置开始和长度(你想要不同的id)
criteria.setProjection(Projections.distinct(Projections.property(uniqueField)));
criteria.setFirstResult(start);
criteria.setMaxResults(length);
List uniqueSubList = criteria.list();
Run Code Online (Sandbox Code Playgroud)
3)重置投影并获得与id匹配的明显结果
criteria.setProjection(null);
criteria.setFirstResult(0); criteria.setMaxResults(Integer.MAX_VALUE);
criteria.add(Restrictions.in(uniqueField, uniqueSubList));
criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
List searchResults = criteria.list();
//and now, however you want to return your results
Map<String, Object> searchResultsMap = new HashMap<String, Object>();
searchResultsMap.put("searchResults", searchResults);
searchResultsMap.put("totalResultCount", totalResultCount);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
20019 次 |
| 最近记录: |