11

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 には、この動作を制御する何かがありますか?

4

3 に答える 3

2

これは遅すぎるかもしれませんが、hibernate はデフォルトの jpa fetchtype オプションをサポートしていないようです

@OneToMany(orphanRemoval = false, fetch = FetchType.EAGER)

休止状態固有のものを使用する必要があります。

@LazyCollection(LazyCollectionOption.FALSE)
于 2014-02-19T05:46:27.993 に答える
0

これを修正する方法はわかりませんが、少しリファクタリングすると役立つと思います。アイデアは、コードを@PostConstruct

たとえば、クラスは次のようになります。

@Entity  
public class A {  
    // ...
    @Transient
    int t;

@OneToMany(orphanRemoval = false, fetch = FetchType.EAGER)  
private List listOfX;  

@PostConstruct
public void calculateT() {
    t = 0;
    for (X x : listOfX)
        t = t + x.someMethod();
}

}

サーバーは、Bean のすべてのコンテナー サービスの初期化が完了するとすぐに PostConstruct を呼び出します。

于 2010-12-22T09:37:28.287 に答える