web-dev-qa-db-ja.com

Spring-Data FETCH JOIN with Pagingが機能しない

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呼び出しは次の例外をスローします。

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からのカウントクエリですが、どうすれば修正できますか?

28

最も簡単な方法は、@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, …);
52
Oliver Drotbohm

あるいは、Springの最新バージョン(JPA 2.1仕様をサポート)では、次のようなエンティティグラフを使用できます。

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

もちろん、名前付きエンティティグラフも機能します。

5
Piotr Tempes

@QuerycountQuery paramを指定する必要があります。これで、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);
2
Max

countProjectionをお試しください

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