LoginSignup
2
0

More than 3 years have passed since last update.

JPAで複数のOneToManyでjoin fetchするとMultipleBagFetchException

Posted at

JPAで@OneToManyを複数定義して両者をjoin fetchで取得しようとすると、下記のような実行時例外になることがある。

Caused by: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags: [jpa.sample2.Tweet.reTweets, jpa.sample2.Tweet.favorites]
    at org.hibernate.loader.BasicLoader.postInstantiate(BasicLoader.java:76) ~[hibernate-core-5.4.20.Final.jar:5.4.20.Final]
    at org.hibernate.loader.hql.QueryLoader.<init>(QueryLoader.java:110) ~[hibernate-core-5.4.20.Final.jar:5.4.20.Final]

状況

説明用のスキーマとして、一つのtweetに複数のReTweetと複数のFavorite、というテーブルを想定する。javaのentityとしては以下のような感じ。

@NoArgsConstructor
@AllArgsConstructor
@Entity
@Data
public class Tweet {
    @Id
    Long id;

    String value;

    @OneToMany
    @JoinColumn(name = "tweetId")
    List<ReTweet> reTweets;

    @OneToMany
    @JoinColumn(name = "tweetId")
    List<Favorite> favorites;
}
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Data
public class ReTweet {
    @Id
    Long id;
    Long tweetId;
    String value;
}
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Data
public class Favorite {
    @Id
    Long id;
    Long tweetId;
    String value;
}

JPQLは以下のようにjoin fetchを2回使用する。

@Repository
public interface TweetRepository extends JpaRepository<Tweet, Long>  {  
    @Query("select distinct t from Tweet t "
            + " left join fetch t.reTweets "
            + " left join fetch t.favorites"
            + " order by t.id")
    List<Tweet> list2();
}

こうすると上記の実行時例外となる。

解決策

このケースの場合はListSetに変えればよい。

    @OneToMany
    @JoinColumn(name = "tweetId")
    Set<ReTweet> reTweets;

    @OneToMany
    @JoinColumn(name = "tweetId")
    Set<Favorite> favorites;

またはMapでも良い。

    @OneToMany
    @JoinColumn(name = "tweetId")
    Map<Long, ReTweet> reTweets;

    @OneToMany
    @JoinColumn(name = "tweetId")
    Map<Long, Favorite> favorites;

もしくは、単一のJPQLを諦めて複数に分割する、というやり方も考えられる。

    @Query("select distinct t from Tweet t "
            + " left join fetch t.reTweets "
            + " order by t.id")
    List<Tweet> list3();

    @Query("select distinct t from Tweet t "
            + " left join fetch t.favorites"
            + " order by t.id")
    List<Tweet> list4();
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0