该查询可能基于给定参数是否为空而具有可选谓词。
例如,如果给定“code”参数不为null,则查询变为“select * from USERS where code = :code”;
据我所知,我不能使用@Query注释来实现这一点。我可以实现自定义存储库并使用EntityManager创建动态查询。 但是,我不确定如何将“Pageable”与其集成以获取分页结果。
我该如何实现这一点?
使用QueryDSL(作为Criteria API的替代品),在Spring Data中非常容易实现这一点。它通过QueryDSLPredicateExecutor的以下方法支持开箱即用,如果不需要应用任何限制,只需将Predicate传递为null即可:
Page<T> findAll(com.mysema.query.types.Predicate predicate,
Pageable pageable)
如果您不能使用QueryDSL,但是如果您查看以下一系列教程,您可能会得到一些想法。
实际上,文中的作者在他指南的第9部分评论中讨论了您所面临的情况。
对于querydsl查询获取页面结果有一定的复杂性,因为你需要两个查询:一个用于获取条目总数,另一个用于获取页面中所需的条目列表。您可以使用以下超类:
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);
}
}
您需要使用querydsl
,并根据非空参数构建您的where
,例如
BooleanBuilder where = new BooleanBuilder();
...
if(code != null){
where.and(YOURENTITY.code.eq(code));
}
执行查询后
JPAQuery query = new JPAQuery(entityManager).from(..)
.leftJoin( .. )
...
.where(where)
MaPage<YOURENTITY> page = new MaPage<YOURENTITY>();
page.number = pageNumber+1;
page.content = query.offset(pageNumber*pageSize).limit(pageSize).list(...);
page.totalResult = query.count();
public class MaPage<T> {
public List<T> content;
public int number;
public Long totalResult;
public Long totalPages;
...
}
这个方法可以工作,但如果你的查询中包含了fetch语句,那么就会出现这个警告:
nov. 21, 2014 6:48:54 AM org.hibernate.hql.internal.ast.QueryTranslatorImpl list
WARN: HHH000104: firstResult/maxResults specified with collection fetch; applying in memory!
这会拖慢你的请求速度。所以解决方案是去掉fetch,并定义一个@BatchSize(size=10)
,使用Hibernate.initialize(....)
来获取集合和其他类型的数据。