JPA2/Hibernate を使用して、エンティティ X への一方向マッピングを持つエンティティ A を作成しました (以下を参照)。A の中には、@PostLoad メソッドを使用して計算しようとしている一時的なメンバー "t" もあります。計算には、関連する X へのアクセスが必要です。
@Entity
public class A {
// ...
@Transient
int t;
@OneToMany(orphanRemoval = false, fetch = FetchType.EAGER)
private List listOfX;
@PostLoad
public void calculateT() {
t = 0;
for (X x : listOfX)
t = t + x.someMethod();
}
}
ただし、このエンティティをロードしようとすると、「org.hibernate.LazyInitializationException: ロード コレクションへの不正なアクセス」エラーが発生します。
at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:363)
at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:108)
at org.hibernate.collection.PersistentBag.get(PersistentBag.java:445)
at java.util.Collections$UnmodifiableList.get(Collections.java:1154)
at mypackage.A.calculateT(A.java:32)
デバッグ中に休止状態のコード (AbstractPersistentCollection.java) を見ると、次のことがわかりました。
1) "listOfX" メンバーが初期化される前に @PostLoad メソッドが呼び出さ
れる
protected final void initialize(boolean writing) {
if (!initialized) {
if (initializing) {
throw new LazyInitializationException("illegal access to loading collection");
}
throwLazyInitializationExceptionIfNotConnected();
session.initializeCollection(this, writing);
}
}
これを修正する唯一の方法は、@PostLoad の使用を停止し、初期化コードを getT() アクセサーに移動して、同期ブロックを追加することです。ただし、それは避けたい。
@PostLoad が呼び出される前に熱心なフェッチを実行する方法はありますか? それを行うためのJPA機能を知らないので、知らないことがあるといいのですが。
また、おそらく Hibernate の独自の API には、この動作を制御する何かがありますか?