복붙노트

[SPRING] 페이징이있는 Spring-Data FETCH JOIN이 작동하지 않습니다.

SPRING

페이징이있는 Spring-Data FETCH JOIN이 작동하지 않습니다.

JOIN FETCH를 사용하여 하위 엔티티와 함께 ​​엔티티를 가져 오는 HQL을 사용하려고하는데 모든 결과를 원한다면이 작업이 제대로 작동하지만 페이지를 원한다면 대소 문자가 아님

내 항목 :

@Entity
@Data
public class VisitEntity {

    @Id
    @Audited
    private long id;

    .
    .
    .   

    @OneToMany(cascade = CascadeType.ALL,)
    private List<VisitCommentEntity> comments;
}

수백만 방문자가 있기 때문에 Pageable을 사용해야하고 다음과 같은 단일 데이터베이스 쿼리에서 주석을 가져와야합니다.

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

HQL 호출은 다음 예외를 throw합니다.

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<VisitEntity> getVenueVisits(@Param("venueId") long venueId,...);

분명히 문제는 Spring-Data의 카운트 쿼리이지만 어떻게 해결할 수 있습니까?

해결법

  1. ==============================

    1.가장 쉬운 방법은 @Query 어노테이션의 countQuery 속성을 사용하여 사용할 사용자 정의 쿼리를 제공하는 것입니다.

    가장 쉬운 방법은 @Query 어노테이션의 countQuery 속성을 사용하여 사용할 사용자 정의 쿼리를 제공하는 것입니다.

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

    2.@Query에 countQuery 매개 변수를 지정해야하며 이제 Page 또는 List를 반환 값으로 사용할 수 있습니다.

    @Query에 countQuery 매개 변수를 지정해야하며 이제 Page 또는 List를 반환 값으로 사용할 수 있습니다.

    @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<VisitEntity> getVenueVisits(@Param("venueId") long venueId,...,
            Pageable pageable);
    
  3. ==============================

    3.Spring의 최신 버전 (JPA 2.1 스펙 지원)에서는 다음과 같이 엔티티 그래프를 사용할 수 있습니다.

    Spring의 최신 버전 (JPA 2.1 스펙 지원)에서는 다음과 같이 엔티티 그래프를 사용할 수 있습니다.

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

    물론 명명 된 엔티티 그래프도 작동합니다.

  4. from https://stackoverflow.com/questions/21549480/spring-data-fetch-join-with-paging-is-not-working by cc-by-sa and MIT license