具有分页的Spring-Data FETCH JOIN不起作用

我正在尝试使用HQL使用JOIN FETCH获取我的实体和子实体,如果我想要所有结果,这可以正常工作但如果我想要一个页面则不是这样

我的实体是

@Entity @Data public class VisitEntity { @Id @Audited private long id; . . . @OneToMany(cascade = CascadeType.ALL,) private List comments; } 

因为我有数百万次访问,我需要使用Pageable,我想在单个数据库查询中获取注释,如:

 @Query("SELECT v FROM VisitEntity v LEFT JOIN FETCH v.comments WHERE v.venue.id = :venueId and ..." ) public Page getVenueVisits(@Param("venueId") long venueId,..., Pageable pageable); 

该HQL调用抛出以下exception:

 Caused by: java.lang.IllegalArgumentException: org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=null,role=com.ro.lib.visit.entity.VisitEntity.comments,tableName=visitdb.visit_comment,tableAlias=comments1_,origin=visitdb.visit visitentit0_,columns={visitentit0_.visit_id ,className=com.ro.lib.visit.entity.VisitCommentEntity}}] [select count(v) FROM com.ro.lib.visit.entity.VisitEntity v LEFT JOIN FETCH v.comments WHERE v.venue.id = :venueId and (v.actualArrival > :date or v.arrival > :date)] at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1374) at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1310) at org.hibernate.ejb.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:309) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 

一旦我删除了分页,一切正常

 @Query("SELECT v FROM VisitEntity v LEFT JOIN FETCH v.comments WHERE v.venue.id = :venueId and ..." ) public List getVenueVisits(@Param("venueId") long venueId,...); 

显然问题是来自Spring-Data的count查询,但是我们如何解决呢?

最简单的方法是使用@Query批注的countQuery属性来提供要使用的自定义查询。

 @Query(value = "SELECT v FROM VisitEntity v LEFT JOIN FETCH v.comments …", countQuery = "select count(v) from VisitEntity v where …") List getVenueVisits(@Param("venueId") long venueId, …); 

您必须为@Query指定countQuery参数,现在您可以使用PageList作为返回值。

 @Query(value = "SELECT v FROM VisitEntity v LEFT JOIN FETCH v.comments WHERE v.venue.id = :venueId and ...", countQuery = "SELECT count(v) FROM VisitEntity v LEFT JOIN v.comments WHERE v.venue.id = :venueId and ..." ) public Page getVenueVisits(@Param("venueId") long venueId,..., Pageable pageable); 

或者在最新版本的Spring(支持JPA 2.1规范)中,您可以使用如下的实体图:

 @EntityGraph(attributePaths = "roles") @Query("FROM User user") Page findAllWithRoles(Pageable pageable); 

当然命名的实体图也可以工作。