2017-01-26 14 views
0

データベースに格納されているツリー構造を構築します。関係は、データベーステーブルのid、parend_idフィールドに基づいて構築されます。私は春のデータと冬眠を使用しています。同じエンティティを持つFetchtype.LAZY

ツリー構造にアクセスするために、エンティティクラス "Node"と "NodeRepository"を構築します。エンティティクラスには属性 "children"があり、それ自身に@OneToMany関係があります。

ノードを取得することは問題ありません。しかし、トランザクション環境の外部での遅延読み込み(「遅延コレクションの初期化に失敗しました」)のために、子をフェッチすることは問題になります。

私はFetchmodeを熱心に変更しました。しかし、それはまた、それ自体との関係のために問題であり、それは、木構造全体がフェッチされることに終わった。

このケースでは、片方の子供の読書を容易にし、反対側の全体の構造を取得しないようにするのがベストプラクティスですか?

+0

私は、完全な答えを書く/重複した質問を探す時間はありませんが、遅延プロパティの条件付き読み込みに依存するように設計されたJPA 2.1の機能である*エンティティグラフ*を読むことをお勧めします。 – Gimby

+0

私はすでに@ NamedEntityGraphを見ましたが、再帰的関係のために私の問題を解決できないと思います。どの時点で、私は子供を得るためのヒントを置かなければならないのですか? – st4rbuck

+0

私はHibernateが仕様を強制する理由を理解していないので、怠惰なコレクションをデタッチされたエンティティにロードすることはできません。個人的にはこれが私がEclipseLinkを好む理由の1つです。なぜなら、EclipseLinkがJPAリファレンス実装であっても、理にかなっていないため、開発者にとっては完全な痛みであるためです。 –

答えて

0

おそらくプロバイダの実装によって異なります。しかし、通常、子コレクションは、コレクションの使用時に初期化されます。したがって、一般的な方法は、取引から出る前にchildren.size()に電話し、結果を捨てることです。

0

引き続きレイジーフェッチタイプを使用して、すべての子がフェッチされるまでにセッションが閉じられていないことを確認できます。あなたのエンティティで熱心な1体の以上の関係を持っている場合

Session session = sessionFactory.openSession(); 
// fetch all required Nodes & all their children by using the same session object 
session.close(); 
+0

どのセッション? OPはJPAを参照しています(タグ内) –

+0

"SessionFactory session_factory = emf.unwrap(SessionFactory.class);を使用してEntityManagerFactoryからセッションを受信しようとしました。子にアクセスする直前にセッションファクトリから新しいセッションを開きます。私はうまくいきませんでした。私は "遅れて役割のコレクションを初期化できませんでした"という例外を得ました。 – st4rbuck

+0

最初に新規に作成したセッションオブジェクトを使用してノードエンティティを取得し、その後に子のリストを取得する必要があります。また、プロジェクトで春を使用している場合は、子リストを@Transactionalアノテーションで取得するメソッドにマークを付けるだけで、実行中のスレッドが終了するまでトランザクションを開いたままにしておくことができます。 –

0

は、あなたが他の人のeagersに注釈@Fetch(FetchMode.SELECT)を含める必要があります:あなたは、単純なDOをすることができます。

fetchmodeの各利用可能なユーザをそれぞれofficial documentationにチェックインしてください。

0

私のニーズに合った解決策があると思います。

まず、私のNodeRepositoryインターフェイスを拡張するカスタムインターフェイスを定義し、追加のメソッド "findOneWithChildrenInit"を実装して実装しました。

public interface NodeRepositoryCustom { 

    public Node findOneWithChildrenInit(Long id); 

} 

public class NodeRepositoryImpl implements NodeRepositoryCustom { 

    @Autowired 
    NodeRepository repo; 

    @Override 
    @Transactional 
    public Node findOneWithChildrenInit(Long id) { 
     Node node = repo.findOne(id); 
     node.getChildren().size(); 
     return node; 
    } 

} 

だから私は決めることができます。子供が必要ないときは、単にfindOne()を呼び出すことができます。それから私はそれらを必要とする、私はfindOneWithChildrenInit()を呼び出します。

関連する問題