web-dev-qa-db-ja.com

Hibernate(JPA)すべての子オブジェクトをロードして熱心なクエリを実行する方法

私の 以前の質問 に関連して、データにアクセスする必要のある複数のスレッドがあるため、すべての子オブジェクトが確実に読み込まれるようにしたい(したがって、遅延読み込みの例外を回避したい)。これを行う方法は、クエリで「fetch」キーワードを使用することだと理解しています(EJB QL)。このような:

select distinct o from Order o left join fetch o.orderLines

Orderのセットを含むOrderLinesクラスを持つモデルを想定しています。

私の質問は、「明確な」キーワードが必要であると思われるということです。それ以外の場合は、OrderごとにOrderLineが返されるようです。私は正しいことをしていますか?

おそらくもっと重要なことですが、どの程度深くても、すべての子オブジェクトを取り込む方法はありますか?約10〜15のクラスがあり、サーバーにはすべてをロードする必要があります... FetchType.EAGERの使用は避けていました。それは常に熱心で、特にWebフロントエンドがすべてをロードすることを意味していました。あなたは何をしますか?私は以前これを試し、その後非常に遅いWebページを取得したことを覚えているようですが、おそらくそれは、2次キャッシュを使用する必要があることを意味しますか?

20
Chris Kimpton

注釈の変更は悪い考えですIMO。実行時に遅延に変更できないため。すべてを遅延させ、必要に応じてフェッチする方がよいでしょう。

マッピングなしで問題を理解できたとは思いません。左結合フェッチは、説明するユースケースに必要なすべてのはずです。もちろん、オーダーラインに親としてオーダーがある場合、すべてのオーダーラインのオーダーが返されます。

14
James Law

EJBQLでfetchキーワードを使用するかどうかはわかりませんが、アノテーションと混同されている可能性があります...

FetchTypeプロパティを関係属性に追加してみましたか?

@OneToMany(fetch = FetchType.EAGER)?

見る:

http://Java.Sun.com/javaee/5/docs/api/javax/persistence/FetchType.htmlhttp://www.jroller.com/eyallupu/entry/ hibernate_exception_simultaneously_fetch_multiple

8
Jeremy

結果トランスフォーマーを使用してみましたか?条件クエリを使用する場合は、結果トランスフォーマーを適用できます(ただし、 ページネーションと結果トランスフォーマーにいくつかの問題があります )。

_Criteria c = ((Session)em.getDelegate()).createCriteria(Order.class);
c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
c.list();
_

em.getDelegate()は、休止状態を使用している場合にのみ機能するハックです。

おそらくもっと重要なことですが、どの程度深くても、すべての子オブジェクトを取り込む方法はありますか?約10〜15のクラスがあり、サーバーにはすべてをロードする必要があります... FetchType.EAGERは常に熱心で、特にWebフロントエンドがすべてをロードすることを意味していたため、使用を避けていましたが、おそらくそれが方法です-それはあなたがすることですか?私は以前これを試し、その後非常に遅いWebページを取得したことを覚えているようですが、おそらくそれは、2次キャッシュを使用する必要があることを意味しますか?

それでも興味がある場合は、このスレッドで同様の質問に回答しました 休止状態のコレクションをシリアル化する方法

基本的に、 dozer と呼ばれる、Beanを別のBeanにマッピングするユーティリティを使用します。これを行うと、すべての遅延ロードがトリガーされます。ご想像のとおり、すべてのコレクションが熱心にフェッチされた場合、これはより効果的に機能します。

3
Miguel Ping

(切り離された)条件クエリを使用して、フェッチモードを設定することで、そのようなことができる場合があります。例えば。、

Session s = ((HibernateEntityManager) em).getSession().getSessionFactory().openSession();
DetachedCriteria dc = DetachedCriteria.forClass(MyEntity.class).add(Expression.idEq(id));
dc.setFetchMode("innerTable", FetchMode.JOIN);
Criteria c = dc.getExecutableCriteria(s);
MyEntity a = (MyEntity)c.uniqueResult();
2
Mike Desjardins

私が行ったことは、コードをリファクタリングしてオブジェクトのマップをエンティティマネージャーに保持し、更新が必要になるたびに、オブジェクトの古いエンティティマネージャーを閉じて新しいエンティティマネージャーを開くことです。 fetchを使用せずに上記のクエリを使用しましたが、それは私のニーズには深すぎます-単純な結合を実行するだけでOrderLinesがプルされます(fetchはさらに深くなります。

これが必要なオブジェクトはわずか20個程度しかないため、20個のエンティティマネージャーを開いていることによるリソースのオーバーヘッドは問題ではないと思います。ただし、これが実行されると、DBAは別の見方をする場合があります...

また、データベースの作業がメインスレッド上にあり、エンティティマネージャーを持つように、作業をやり直しました。

クリス

0
Chris Kimpton

これは、ManyToOneリレーションでのみ機能し、@ ManyToOne(fetch = FetchType.EAGER)がおそらく適切です。

複数のOneToMany関係を熱心に取得することはお勧めできません。また、Jeremyが投稿したリンクを読むことができるため、機能しません。このようなフェッチを実行するために必要なSQLステートメントについて考えてみてください...

0
jrudolph