pagination - query - Paginación JPA de Spring Data(paginable) con consultas dinámicas
spring data pageable custom query (4)
Tengo una consulta simple de la siguiente manera "select * from USERS". También uso Pageable para habilitar la paginación.
Esta consulta puede tener predicados opcionales basados en los parámetros dados que son nulos o no.
Por ejemplo, si el parámetro "código" está dado y no es nulo, entonces la consulta se convierte en "seleccionar * de USUARIOS donde código =: código";
Por lo que sé, no puedo implementar esto usando la anotación @Query. Puedo implementar un repositorio personalizado y usar EntityManager para crear una consulta dinámica. Sin embargo, no estoy seguro de cómo puedo integrar "en página" con eso para recuperar los resultados paginados.
¿Cómo puedo conseguir esto?
Esto es muy fácil de hacer en Spring Data usando QueryDSL (como alternativa a la API de criterios). Se admite fuera de la caja con el siguiente método de QueryDSLPredicateExecutor donde puede pasar nulo como Predicado si no se aplican restricciones:
Page<T> findAll(com.mysema.query.types.Predicate predicate,
Pageable pageable)
El uso de QueryDSL puede no ser una opción para usted; sin embargo, si mira la siguiente serie de tutoriales, es posible que obtenga algunas ideas.
La situación que tiene es realmente discutida por el autor en los comentarios a la parte 9 de su guía.
Obtener resultados de página para consultas querydsl es de alguna manera complicado ya que necesita dos consultas: una para el número total de entradas y otra para la lista de entradas que necesita en la página. Podría usar la siguiente superclase:
public class QueryDslSupport<E, Q extends EntityPathBase<E>> extends QueryDslRepositorySupport {
public QueryDslSupport(Class<E> clazz) {
super(clazz);
}
protected Page<E> readPage(JPAQuery query, Q qEntity, Pageable pageable) {
if (pageable == null) {
return readPage(query, qEntity, new QPageRequest(0, Integer.MAX_VALUE));
}
long total = query.clone(super.getEntityManager()).count(); // need to clone to have a second query, otherwise all items would be in the list
JPQLQuery pagedQuery = getQuerydsl().applyPagination(pageable, query);
List<E> content = total > pageable.getOffset() ? pagedQuery.list(qEntity) : Collections.<E> emptyList();
return new PageImpl<>(content, pageable, total);
}
}
La información aquí es obsoleta. Haga que su repositorio implemente QueryDslPredicateExecutor y que la paginación sea gratuita.
Tienes que usar querydsl
y construir tu where
dependiendo de un parámetro no nulo, por ejemplo
BooleanBuilder where = new BooleanBuilder();
...
if(code != null){
where.and(YOURENTITY.code.eq(code));
}
y luego de ejecutar la consulta
JPAQuery query = new JPAQuery(entityManager).from(..)
.leftJoin( .. )
...
.where(where)
y usa tu propia página
MaPage<YOURENTITY> page = new MaPage<YOURENTITY>();
page.number = pageNumber+1;
page.content = query.offset(pageNumber*pageSize).limit(pageSize).list(...);
page.totalResult = query.count();
Creo MyPage así
public class MaPage<T> {
public List<T> content;
public int number;
public Long totalResult;
public Long totalPages;
...
}
funciona, pero si en su consulta tiene una búsqueda, tendrá esta advertencia
nov. 21, 2014 6:48:54 AM org.hibernate.hql.internal.ast.QueryTranslatorImpl list
WARN: HHH000104: firstResult / maxResults especificado con la obtención de recopilación; aplicando en la memoria!
y ralentizará su solicitud. Por lo tanto, la solución es obtener un paseo de la búsqueda y definir un @BatchSize(size=10)
y usar Hibernate.initialize(....)
para obtener datos en colecciones y otro tipo de objeto.
Cómo ejecutar un JPAQuery con paginación usando Spring Data y QueryDSL