我使用以下提示和灵感解决了这个难题:
-
Limiting resultset using @Query anotations 来自 Koitoer
-
How to order by count() in JPA 来自 MicSim
- 我自己的详尽实验
关于spring-data,我不知道的第一件也是最重要的事情是,即使使用@Query 自定义方法,仍然可以通过简单地将Pageable 对象作为参数传递来创建分页查询。这是 spring-data 文档可以明确说明的内容,因为它虽然非常强大,但绝对不是显而易见的。
太好了,现在是第二个问题 - 我如何在 JPA 中按关联集合的大小对结果进行实际排序?我设法找到了以下 JPQL:
select new package.AwithBCount(count(b.id) as bCount,c) from A a join a.bes b group by a
其中AwithBCount是查询结果实际映射到的类:
public class AwithBCount{
private Long bCount;
private A a;
public AwithBCount(Long bCount, A a){
this.bCount = bCount;
this.a = a;
}
//getters
}
很高兴我现在可以像下面这样简单地定义我的存储库
public interface ARepository extends JpaRepository<A, Long> {
@Query(
value = "select new package.AwithBCount(count(b.id) as bCount,c) from A a join a.bes b group by a",
countQuery = "select count(a) from A a"
)
Page<AwithBCount> findAllWithBCount(Pageable pageable);
}
我赶紧尝试了我的解决方案。完美 - 页面已返回,但当我尝试按 bCount 排序时,我感到很失望。事实证明,由于这是一个 ARepository(不是 AwithBCount 存储库),spring-data 将尝试在 A 中查找 bCount 属性而不是 AwithBCount。所以最后我得到了三个自定义方法:
public interface ARepository extends JpaRepository<A, Long> {
@Query(
value = "select new package.AwithBCount(count(b.id) as bCount,c) from A a join a.bes b group by a",
countQuery = "select count(a) from A a"
)
Page<AwithBCount> findAllWithBCount(Pageable pageable);
@Query(
value = "select new package.AwithBCount(count(b.id) as bCount,c) from A a join a.bes b group by a order by bCount asc",
countQuery = "select count(a) from A a"
)
Page<AwithBCount> findAllWithBCountOrderByCountAsc(Pageable pageable);
@Query(
value = "select new package.AwithBCount(count(b.id) as bCount,c) from A a join a.bes b group by a order by bCount desc",
countQuery = "select count(a) from A a"
)
Page<AwithBCount> findAllWithBCountOrderByCountDesc(Pageable pageable);
}
...以及服务级别的一些附加条件逻辑(可能用抽象存储库实现封装)。所以,虽然不是非常优雅,但这就是诀窍 - 这样(拥有更复杂的实体)我可以按其他属性排序,进行过滤和分页。