2012-02-23 18 views
3

はどのように含めるかpromotionsの負荷を除外することができますか?次のマッピングオブジェクトにマッピングされたコレクションを条件付きでロードするにはどうすればよいですか?

<class name="com.domain.Season" table="cm.pub.jsn_mstr"> 
    <id name="seasonCode" column="season_code" length="1"/> 
    <property name="name" type="string" column="name" length="20"/> 
    <set name="promotions" lazy="false"> 
     <key column="season_code"/> 
     <one-to-many class="com.domain.Promotion" not-found="ignore"/> 
    </set> 
</class> 

を考えますか私はlazy="true"を使用することができますが、私はジャクソンを使用してセッションを閉じた後の結果をシリアル化しています。

public Collection<Season> getSeasons(boolean withPromotions) { 
    final Session session = sessionFactory.getCurrentSession(); 
    try { 
     session.beginTransaction(); 
     return (List<Season>) session.createQuery("from Season s").list(); 
    } finally { 
     session.getTransaction().commit(); 
    } 
} 

UPDATE:遅延読み込みを使用して通報。

上記のgetSeasonsメソッドは、シーズンを取得してからJSON(Spring/MVCのビューリゾルバを使用)をシリアル化して実際にオブジェクトにアクセスしないMVCコントローラで使用されます。遅延でコレクションの結果をロードします(jacksonはすべてのコレクションプロパティでイテレータを呼び出します)。

public Collection<Season> getSeasons(boolean withPromotions) { 
    final Session session = sessionFactory.getCurrentSession(); 
    final List<Season> r; 
    try { 
     session.beginTransaction(); 
     r = (List<Season>) session.createQuery(
       withPromotions 
       ? "from Season s join fetch s.promotions" 
       : "from Season s" 
       ).list(); 
    } finally { 
     session.getTransaction().commit(); 
    } 
    try { 
     for (Season s : r) { 
      for (Promotion p : s.getPromotions()) { 
       // Exception thrown here as we attempted to get an iterator. 
       LOG.debug("Promotion: " + p.getName()); 
      } 
     } 
    } catch (Exception ex) { 
     LOG.error("Couldn't get promotions", ex); 
    } 
    return r; 
} 

そしてもちろんのマッピングはlazy="true"それ以外の場合は、常にコレクションを熱心に読みます持っている必要があり、この時間を:ここで

は、例外がスローされますを示す例です。 promotionsフィールドの

<class name="com.domain.Season" table="cm.pub.jsn_mstr"> 
    <id name="seasonCode" column="jsn_seas" length="1"/> 
    <set name="promotions" lazy="true"> 
     <key column="jpr_seas"/> 
     <one-to-many class="com.domain.Promotion" not-found="ignore"/> 
    </set> 
</class> 

データ型がCollection<Promotion>です。

答えて

0

これを行うことができる唯一の方法は、コレクションをマップしないで、代わりに2つのクエリを送信し、コレクションに自分自身を追加することです。

これは、1 + n(nは最初のクエリから取得された行)の代わりに2つのクエリのみを送信するため、関連付けをより詳細に制御し、パフォーマンスを向上させます。

2

Hibernate.initialize()を使用すると、プロキシからコレクションを初期化できます。あなたの例では、以下のコードを追加します。 APIドキュメントから

public Collection<Season> getSeasons(boolean withPromotions) { 
    final Session session = sessionFactory.getCurrentSession(); 
    try { 
     session.beginTransaction(); 
     List<Season> list = session.createQuery("from Season s").list(); 
     for(Season s : list){ 
      if(condition){ 
       Hibernate.initialize(s.getPromotions()); 
      } 
     } 
     return list; 


    } finally { 
     session.getTransaction().commit(); 
    } 
} 

この意志

静的メソッドHibernate.initialize()やHibernate.isInitialized()、遅延初期化のコレクションやプロキシを扱うときに便利な方法をアプリケーションに提供。 Hibernate.initialize(cat)は、Sessionがまだ開いている限り、プロキシcatの初期化を強制します。 Hibernate.initialize(cat.getKittens())は、子猫のコレクションにも同様の効果があります。

API hereまたは例hereを参照してください。

+0

これは、レイジーフラグをオンにすることを意味しますが、セッションが閉じられてからJacksonが例外をスローします。 –

+0

セッションを閉じる前にこのメソッドを呼び出す必要があります。これは、休止状態で** Lazy **動作を動的に制御する方法です。私はあなたの方法でのその使用法で私の答えを更新しました。 – ManuPK

+0

マヌーありがとう、私は問題を正しく説明していないと思う。ジャクソンがシリアル化しようとしたときに返されたシーズンが私のコントローラに戻ってくると、プロモーションプロパティが読み込まれ、セッションが閉じられると例外が発生します。 –

3

このお試しください:休止状態の参照から

session.createQuery("from Season s join fetch s.promotions").list(); 

を: 参加する「フェッチは、」関連や値のコレクションが、単一の選択を使用して親オブジェクトとともに初期化することができます。

+0

これは良いコレクションですが、コレクションにアクセスしたときにコレクションをロードしようとしないようにhibernateに指示する方法はありますか?セッションが終了した後に 'season.getPromotions()'を試行した場合、プロモーションを読み込もうとしますが、これを防ぐ方法はありますか? –

+0

愚かな冬眠..なぜこれがあなたのために動作しないのかわかりません@BrettRyan。同様のクエリを作成したので、問題なくセッションを閉じた後にゲッターを使ってコレクションにアクセスできます。 Season(例外をスローするgetterを呼び出すもの)のインスタンスが、getSeasons(boolean)関数から返されるものとまったく同じものであることを確認してください。何か不足していますか?私の回答とManuPkの両方が遅延ロードの問題に対する有効な解決策であるため、おそらくもっと情報を追加するべきです。多分、あなたのコードのどこかには、おそらく原因があります。がんばろう。 – buritos

+0

+1井戸は@ buritosです。 ** join fetch **がコレクションを初期化することを知っておくとよいでしょう。 – ManuPK

0

あなたの問題は、基本的にジャクソンです。休止状態ではありません。

次のいずれかの適切

1)コントロール・ジャクソン、あなたが実際に必要なデータを送信するために - あなたはそれが上のプル "したくないものを避けます。

2)使っ春の「OpenSessionInViewFilter」または類似スレッドローカルにセッションを結合し、ビューが実行されるまで開いて、それを残して - まだビューで&負荷コレクション「を引っ張る」にジャクソンを有効にしますレンダリングステージ。

3)または同じテーブルに2つの異なるクラス(1つの詳細、軽量)をマップし、実際に必要なものを取得します。

SeasonLiteはおそらくSeasonの祖先かもしれませんが、Hibernateで継承をマッピングしていないことに注意してください。同じテーブルの2つの別々のビューをマッピングしています。

PS: 'getSomeData(boolean retrieveThisData)'のようなメソッドはよくあるパターンのようです。私は以前何度も見ました。

0

申し訳ありませんが、これは非常に遅い回答ですが、私はあなたの質問を見つけたときに何か他のものを探していました。

答えのいくつかで既に述べたように、問題はHibernateがレイジーローディングコレクションに 'プレースホルダー' PersistentCollectionを使用することです。コレクションにアクセスしたときにHibernateがコレクションに書き込もうとするのを止めるには、クエリによって返されるSeasonエンティティのそれぞれの実際のPromotionsリストをnullにすることができます。コードでは、このような何か:nullにPromotionsを設定

if (!withPromotions) { 
    for (Season s : r) { 
     s.setPromotions(null); 
    } 
} 

は、Hibernateのコレクションオブジェクトへの参照をクリアします。あなたはセッションの外でこれを行うことができるはずです。

public boolean isPromotionsLoaded() { 
    if (((promotions instanceof org.hibernate.collection.PersistentCollection) 
      && !((org.hibernate.collection.PersistentCollection) promotions).wasInitialized()) 
      || (getPromotions() == null)) { 
     return false; 
    } else { 
     return true; 
    } 
} 

私たちが安全にコレクションにアクセスできるかどうか、我々は見つけるためにこれらのメソッドを使用することができます。私たちは何

は次のように私たちのコレクションのそれぞれについて、当社のエンティティのメソッドを作成することです。

とにかく、これが誰かを助けてくれることを願っています。

関連する問題