34

大きなアプリケーションで EAGER の関係に問題があります。このアプリケーションの一部のエンティティはEAGER、他のエンティティと関連付けられています。これは、一部の機能では「毒」になります。

私のチームはこの機能を最適化する必要がありますが、アプリケーション全体をリファクタリングする必要があるため、フェッチ タイプを LAZY に変更することはできません。

それで、私の質問: 返されたエンティティの EAGER 関連付けを無視して特定のクエリを実行する方法はありますか?

例: このエンティティ Person がある場合、Person を検索するクエリを実行するときにアドレス リストを取得したくありません。

@Entity
public class Person {

  @Column
  private String name;

  @OneToMany(fetch=FetchType.EAGER)
  private List<String> address;

}

Query query = EntityManager.createQuery("FROM Person person");
//list of person without the address list! But how???
List<Person> resultList = query.getResultList();

ありがとう!

更新しました

私が見つけた唯一の方法は、エンティティを返さず、エンティティの一部のフィールドのみを返すことです。しかし、エンティティ (私の例ではエンティティ) を返すことができる解決策を見つけたいと思いますPerson

Hibernateで同じテーブルを2回マップできるかどうか考えています。このようにして、EAGER アソシエーションなしで同じテーブルをマッピングできます。これはいくつかのケースで私を助けます...

4

7 に答える 7

14

JPA 2.1 (Hibernate 4.3+) を使用している場合は、@NamedEntityGraph で目的を達成できます。

基本的に、次のようにエンティティに注釈を付けます。

@Entity
@NamedEntityGraph(name = "Persons.noAddress")
public class Person {

  @Column
  private String name;

  @OneToMany(fetch=FetchType.EAGER)
  private List<String> address;

}

次に、ヒントを使用して、次のようにアドレスなしで Person をフェッチします。

EntityGraph graph = this.em.getEntityGraph("Persons.noAddress");

Map hints = new HashMap();
hints.put("javax.persistence.fetchgraph", graph);

return this.em.findAll(Person.class, hints);

このテーマの詳細については、こちらを参照してください。

フェッチ グラフを使用すると、 @NamedEntityGraph 内に配置したフィールドのみが積極的にフェッチされます。

ヒントなしで実行されるすべての既存のクエリは同じままです。

于 2015-12-31T12:57:53.937 に答える
8

更新(2020 年 9 月 6 日):

この問題は 5.4.11 バージョンで解決されました。今はテストできませんが、グラフに含まれていない JPA エンティティ グラフ属性は、宣言されていてもアンロードされたままになることが予想されますEAGER

元の答え

何年も経った今でも、Hibernateでは EAGER マッピングをオーバーライドすることはまだできません。最新の Hibernate ドキュメント(5.3.10.Final)から:

JPA 標準では、実行時に javax.persistence.fetchgraph ヒントを使用して EAGER フェッチ アソシエーションをオーバーライドできると規定されていますが、現在、Hibernate はこの機能を実装していないため、EAGER アソシエーションを遅延フェッチすることはできません。詳細については、 HHH-8776 Jira イシューを確認してください。

JPQL クエリを実行するときに、EAGER アソシエーションが省略されている場合、Hibernate は熱心にフェッチする必要があるすべてのアソシエーションに対してセカンダリ選択を発行します。これにより、dto N+1 クエリの問題が発生する可能性があります。

このため、LAZY アソシエーションを使用して、クエリごとに熱心にフェッチすることをお勧めします。

と:

EAGER フェッチ戦略はクエリごとに上書きできないため、関連付けは必要なくても常に取得されます。さらに、JPQL クエリで EAGER アソシエーションを JOIN FETCH するのを忘れた場合、Hibernate はそれをセカンダリ ステートメントで初期化するため、N+1 クエリの問題が発生する可能性があります。

于 2018-12-20T10:54:25.297 に答える
2
  1. はい、2 つのエンティティ クラスを同じテーブルにマップできます。これは有効な回避策です。ただし、両方のタイプのインスタンスが同じ永続コンテキストに同時に存在する状況に注意してください。これは、一方のタイプのエンティティ インスタンスの更新が他方のタイプの同じインスタンスに反映されないためです。また、そのようなエンティティの第 2 レベルのキャッシュはより複雑になります。
  2. フェッチ プロファイルも興味深いものですが、現時点では非常に制限されており、結合スタイルのフェッチ プロファイルでのみデフォルトのフェッチ プラン/戦略をオーバーライドできます (遅延関連付けを熱心にすることはできますが、その逆はできません)。ただし、このトリックを使用してその動作を逆転させることができます。デフォルトで関連付けを遅延させ、すべてのセッション/トランザクションに対してデフォルトでプロファイルを有効にします。次に、遅延読み込みが必要なトランザクションでプロファイルを無効にします。
于 2015-12-30T21:55:36.310 に答える
2

実際にこれを試したことはありませんが、試してみる価値はあります...セッションファクトリが注入または他の手段を介してDAOレイヤーで利用可能であると仮定すると、(おそらく新しい)DAOメソッドで同様のものを実装できます:

List<Person> result = (List<Person>) sessionFactory.getCurrentSession()
        .createCriteria(Person.class)
        .setFetchMode("address", FetchMode.LAZY)
        .list();
return result;
于 2013-07-25T04:16:47.313 に答える