J'ai une requête simple comme suit "sélectionnez * des utilisateurs". J'utilise aussi Pageable pour activer la pagination.
Cette requête peut avoir des prédicats facultatifs basés sur des paramètres nuls ou nuls.
Par exemple, si le paramètre "code" est donné et non null, la requête devient "Select * from USERS où code =: code";
Autant que je sache, je ne peux pas l'implémenter avec l'annotation @Query. Je peux implémenter un référentiel personnalisé et utiliser EntityManager pour créer une requête dynamique . Cependant, je ne sais pas comment intégrer "Pageable" à celui-ci pour obtenir des résultats paginés.
Comment puis-je atteindre cet objectif?
Ceci est très facile à faire dans Spring Data en utilisant QueryDSL (comme alternative à l’API critère). Il est pris en charge immédiatement avec la méthode suivante de QueryDSLPredicateExecutor, dans laquelle vous pouvez simplement passer null comme prédicat si aucune restriction ne doit être appliquée:
Page<T> findAll(com.mysema.query.types.Predicate predicate,
Pageable pageable)
QueryDSL n'est peut-être pas une option pour vous. Toutefois, si vous regardez la série de didacticiels suivante, vous aurez peut-être des idées.
Le scénario que vous avez est en fait discuté par l'auteur dans les commentaires de la partie 9 de son guide.
Obtenir les résultats de page pour les requêtes querydsl est quelque peu compliqué, car vous avez besoin de deux requêtes: une pour le nombre total d'entrées et l'autre pour la liste des entrées dont vous avez besoin dans la page . Vous pouvez utiliser la superclasse suivante:
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);
}
}
Vous devez utiliser querydsl
et construire votre where
en fonction du paramètre not null, par exemple
BooleanBuilder where = new BooleanBuilder();
...
if(code != null){
where.and(YOURENTITY.code.eq(code));
}
et après exécuter la requête
JPAQuery query = new JPAQuery(entityManager).from(..)
.leftJoin( .. )
...
.where(where)
et utilisez votre propre page
MaPage<YOURENTITY> page = new MaPage<YOURENTITY>();
page.number = pageNumber+1;
page.content = query.offset(pageNumber*pageSize).limit(pageSize).list(...);
page.totalResult = query.count();
Je crée MyPage comme ça
public class MaPage<T> {
public List<T> content;
public int number;
public Long totalResult;
public Long totalPages;
...
}
cela fonctionne, mais si dans votre requête, vous avez un aller chercher, alors tu vas avoir cet avertissement
nov. 21, 2014 06:48:54 org.hibernate.hql.internal.ast.QueryTranslatorImpl list
WARN: HHH000104: firstResult/maxResults spécifiés avec la récupération de collection; appliquer en mémoire!
et cela ralentira votre demande. La solution consiste donc à contourner le processus d’extraction, à définir une fonction @BatchSize(size=10)
et à utiliser Hibernate.initialize(....)
pour récupérer des données dans des collections et d’autres types d’objets.
Comment exécuter une requête JPAQuery avec une pagination à l'aide de Spring Data et QueryDSL
Les informations ici sont obsolètes. Demandez à votre référentiel d'implémenter/ QueryDslPredicateExecutor et la pagination est gratuite.