web-dev-qa-db-ja.com

JPAを使用したHibernateでのEAGERタイプの複数フェッチ

以下を含むエンティティがあります。

_@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "assessment")
@OrderBy(value = "order ASC")
private List<AssessmentPart> assessmentParts = new LinkedList<>();

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "assessment")
private List<AssessmentText> texts = new LinkedList<>();
_

ご覧のように、2つのコレクションを積極的にロードする必要があります。これは機能せず、Hibernateは例外をスローします。

_Caused by: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags
_

これは、Hibernateが一度に複数のコレクションを取得できないためです。ただし、ListSetに変更し、LinkedListHashSetに変更すると、この部分は正常に機能しますが、他の部分-より厄介な問題が発生します。

次を使用してデータベースからエンティティを取得しようとしているとき:

_entityManager.find(entityClass, primaryKey);
_

それは失敗します:

_org.hibernate.AssertionFailure: null identifier
_

findメソッドに渡すIDがnullではないことを確認しました。デバッグしましたが、これは確かです。 Hibernate内で何らかの形で消えます。

コレクションタイプをLAZYに変更すると、すべてがエラーなしで機能しますが、EAGERを使用する必要がある状況があります。

誰かがそれを修正する方法を持っていますか?セットはあるがアサーションエラーの発生を防ぐか、リストはあるが複数のフェッチバッグエラーを避けることができます。

使っています:

_Hibernate 4.2.2.Final
Tomcat 7
JPA 2.0
JDK 1.7
_

[〜#〜] edit [〜#〜]

@Fetch(FetchMode.SELECT)を追加すると問題が修正され、EAGERタイプで複数のリストを使用できることを発見しましたが、Hibernate固有の注釈を使用しないことでこれを解決できますか?そして、そもそも問題を解決したのはなぜですか?

33
user2219247

この問題の根本的な原因は、HibernateがSQLクエリ結果をフェッチするときに、どの子要素がどのコレクションに属しているかを知る簡単な方法がないことです。例付きの詳細な説明については、 このブログエントリ を参照してください。要約すると、次の回避策があります。

  • Subselect @Fetch(FetchMode.SELECT)を使用して各コレクションを個別にロードします
  • インデックス列@IndexColumn(name="LIST_INDEX")を追加して、バッグではなくリストの使用を強制します
  • Setのような順不同のコレクションを使用します。
60
Maksym Demidas

Hibernateを使用していて、Hibernateアノテーションの使用を気にしない場合:

コレクションフィールドに以下の注釈を付けます。

@LazyCollection(LazyCollectionOption.FALSE)

@OneToManyアノテーションからfetchType属性を忘れずに削除してください。

15
willome