Spring Data JPA において MultipleBagFetchException と LazyInitializationException のいずれかの例外が投げられる

#概要
Spring Data JPA において、下記のような構成のエンティティを作成したところ、MultipleBagFetchException が発生しました。

```Parent.java
@Entity
@Table(name = "parent")
@Getter
public class Parent {

    @Id
    private int id;

    @Column(name = "child_id", nullable = false, updatable = false, insertable = false)
    private int childId;

    @ManyToOne
    @JoinColumn(name = "child_id")
    private Child child;
}
```
```Child.java
@Entity
@Table(name = "child")
@Getter
public class Child {
    @Id
    private int id;

    @OneToMany(mappedBy = child)
    private List<Parent> parents;

    @OneToMany(mappedBy = "child", fetch = FetchType.EAGER)
    private List<SubChild1> subChild1;

    @OneToMany(mappedBy = "child", fetch = FetchType.EAGER)
    protected List<SubChild2> subChild2;
}
```

```SubChild1.java

@Entity
@Table(name = "sub_child1")
@Getter
public class SubChild1 {
    private Child child;
}
```
```SubChild2.java

@Entity
@Table(name = "sub_child2")
@Getter
public class SubChild2 {
    private Child child;
}
```

```error.log
Caused by: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags: [Parent.child, Child.subChild1, Parent.subChild2]
    at org.hibernate.loader.BasicLoader.postInstantiate(BasicLoader.java:75)
```

#詳細

[こちらのページ](https://chandanpandey.com/tag/multiplebagfetchexception/)と実際の動作から、どうやら、FetchType.EAGER において、Hibernate は 2 層までの Collection のネストを許可していますが、3 層までのネストを許可していないことが問題のようでした。

>*JPA allows only two level of nesting for collection, Parententity->Childentity is fine but it does not allow Parententity->childentity->SubChildEntity
*Using List for collection instead of SET -remember a SET guarantees unique elements while list does not

そのため、FetchType.LAZY にてデータを取得しようとした結果、今度は、LazyInitializationException　が発生することになりました。

[こちらのページ](http://www.pwv.co.jp/~take/TakeWiki/index.php?Hibernate%E3%81%AELazy%20initialize%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%A7%E3%83%93%E3%83%A5%E3%83%BC%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84) と実際の動作から Lazy で List にアクセスした際、すでに DB のコネクションが閉じてしまっていたために、データの Fetch ができない状況にあるようでした。

>どうやらビューでコレクションの要素であるLineItemを遅延初期化(lazily initialize)しようとした時に、 Hinbernateのsessionがクローズしていたので例外が発生みたいです。FetchType.LAZY も立ち行かなくなりました。

>そこで、ネット"Spring Hibernate Lazy initialize error" をキーに検索すると

>とあるITエンジニアの業務手帖
に同様のケースが報告されていました。

>解決策としては、Hibernateマッピングファイルのlazy属性をfalseにするというものでした。 そこで、以下のようにOrderのbagタグにlazy="false"を入れ

#解決策
[こちらのページ](http://blog.eyallupu.com/2010/06/hibernate-exception-simultaneously.html) から一部の型を List から Set に変えることで問題が解決できました。

>The third solution is to replace java.util.List and java.util.Collection with java.util.Set. We have to think about it - do we really need a List/Collection (a bag)? In many cases the only reason to use a List is that we are used to.

英語力が低く、お恥ずかしい限りですが、Bag は List のように、重複を許容するオブジェクトのようです。
日本語にしてみると、「複数Bags取得例外」となり、まさに現象と一致した動作です。
クラスについては下記のように修正。

```Child.java
@Entity
@Table(name = "child")
@Getter
public class Child {
    @Id
    private int id;

    @OneToMany(mappedBy = child)
    private Set<Parent> parents;

    @OneToMany(mappedBy = "child", fetch = FetchType.EAGER)
    private Set<SubChild1> subChild1;

    @OneToMany(mappedBy = "child", fetch = FetchType.EAGER)
    protected Set<SubChild2> subChild2;
}
```

補足 : Set について

[公式ページ](https://docs.oracle.com/javase/jp/6/api/java/util/Set.html)　を確認したところ、Set は重複を許可しないオブジェクトのようです。

>重複要素のないコレクションです。すなわち、セットは、e1.equals(e2) である e1 と e2 の要素ペアは持たず、null 要素を最大 1 つしか持ちません。その名前が示すように、このインタフェースは、数学で言う集合の抽象化オブジェクトをモデル化します。  

>Set インタフェースは、Collection インタフェースから継承した規定だけでなく、すべてのコンストラクタの規約、および add、equals、hashCode の各メソッドの規約に追加の規定を適用します。便宜上、ほかの継承メソッドの宣言もここに含まれます。これらの宣言に付随する仕様は Set インタフェースに合わせて調整済みですが、追加規定は含まれていません。  

今回の要件では、重複が発生することはありえませんでしたし、NULL も発生しないのでめでたく解決となりました。