メソッドのJPAフェッチタイプを変更する方法はありますか?
-
10-07-2019 - |
質問
エンティティオブジェクトを編集せずに、単一のメソッドでJPAフェッチタイプを変更する方法はありますか
JPAエンティティクラスで構成される共有ORMレイヤーがあります。このORMレイヤーには、2つのDAOレイヤーがアクセスします。 1つのDAOは私のWebアプリケーション用であるため、レイジーフェッチが必要であり、もう1つのDAOはスレッドセーフであるために積極的なフェッチが必要です。
これは、私のスレッドセーフDAOのメソッド例です
@PersistenceContext(unitName = "PersistenceUnit", type = PersistenceContextType.TRANSACTION)
private EntityManager em;
public ErrorCode findErrorCodeById(short id) {
return (ErrorCode) em.createNamedQuery("ErrorCode.findById").
setParameter("id", id).getSingleResult();
}
このメソッド(またはクラス全体)で積極的なフェッチを使用するにはどうすればよいですか
解決
エンティティの関連付け(@ OneToOne、@ OneToMany、@ ManyToOne)はフェチ遅延(FetchType.Lazy)であると想定しています
次に、2つの方法が考えられます。
A。レイジーの関連付けを取得する2つのjpaクエリ(休止状態のデフォルトの方法)と、関連付けの積極的な読み込みを明示的に強制する2番目のクエリを記述します(クエリの" fetch"キーワードを参照)。
Query q = HibernateUtil.getSessionFactory().getCurrentSession() .createQuery("select c from Category as c" + " left join fetch c.categorizedItems as ci" + " join fetch ci.item as i");
B。 Hibernate.initialize(entity)を使用して、エンティティを取得した後、エンティティの遅延リレーションの強制的な読み込みを強制します(例:ファインダー経由)
ErrorCode lazyCode = findErrorCodeById(1); // eager load associations Hibernate.initialize(lazyCode);
他のヒント
JPAでは、注釈またはxmlマッピングファイルのいずれかで、各永続属性にフェッチモードが指定されます。
つまり、目標を達成するためのJPAベンダーにとらわれない方法は、DAOレイヤーごとに個別のマッピングファイルを持つことです。残念ながら、これにはマッピングファイルごとに個別のPersistenceUnitが必要になりますが、少なくとも同じエンティティクラスと同じJPQLクエリを共有できます。
コードスケルトンが続きます。
persistence.xml:
<persistence>
<persistence-unit name="dao-eager">
<mapping-file>orm-eager.xml</mapping-file>
</persistence-unit>
<persistence-unit name="dao-lazy">
<mapping-file>orm-lazy.xml</mapping-file>
</persistence-unit>
</persistence>
orm-eager.xml:
<entity-mappings>
<entity class="ErrorCode">
<attributes>
<basic name="name" fetch="EAGER"/>
</attributes>
</entity>
</entity-mappings>
orm-lazy.xml:
<entity-mappings>
<entity class="ErrorCode">
<attributes>
<basic name="name" fetch="LAZY"/>
</attributes>
</entity>
</entity-mappings>
それは、DAOレイヤーの適切なpersistence-unitのEntityManagerFactoryを作成するだけの問題です。
実際には、2つのマッピングファイルは必要ありません。エンティティでLAZYまたはEAGERを注釈として指定し、XMLマッピングファイルで反対を指定できます(ただし、2つの永続性ユニットが必要です)。
上記のHibernateソリューションよりも少しコードが多いかもしれませんが、アプリケーションは他のJPAベンダーに移植可能でなければなりません。
余談ですが、OpenJPAはFetchGroups(JDOから借用した概念)を使用して、上記のHibernateソリューションと同様の機能を提供します。
最後の警告、FetchType.LAZYはJPAのヒントです。プロバイダーは必要に応じて行を積極的にロードできます。
リクエストごとに更新。
このようなエンティティを検討してください:
@Entity
public class ErrorCode {
// . . .
@OneToMany(fetch=FetchType.EAGER) // default fetch is LAZY for Collections
private Collection myCollection;
// . . .
}
この場合、2つの永続性ユニットが必要ですが、orm-lazy.xmlのみが必要です。より現実的なシナリオを反映するようにフィールド名を変更しました(コレクションとBLOBのみがデフォルトでFetchType.LAZYを使用します)。したがって、結果のorm-lazy.xmlは次のようになります。
<entity-mappings>
<entity class="ErrorCode">
<attributes>
<one-to-many name="myCollection" fetch="LAZY"/>
</attributes>
</entity>
</entity-mappings>
そしてpersistence.xmlは次のようになります:
<persistence>
<persistence-unit name="dao-eager">
<!--
. . .
-->
</persistence-unit>
<persistence-unit name="dao-lazy">
<!--
. . .
-->
<mapping-file>orm-lazy.xml</mapping-file>
</persistence-unit>
</persistence>
OpenJPAについて誰も言及していないので、ここに答えを掲載します。
OpenJPAでは、以前に遅延設定されたコレクションとフィールドを以下のように積極的にロードできます
OpenJPAEntityManager kem = OpenJPAPersistence.cast(em);
kem.getFetchPlan().addField(Order.class, "products");
TypedQuery<Order> query = kem.createQuery(yourQuery, Order.class);
リファレンス: http: //openjpa.apache.org/builds/1.0.3/apache-openjpa-1.0.3/docs/manual/ref_guide_fetch.html
JPA2で EntityGraphs を使用します。これにより、取得する関連エンティティを定義できます。
https://docs.oracle.com/javaee/7 /tutorial/persistence-entitygraphs002.htm https://docs.oracle.com/javaee/7/tutorial/ persistence-entitygraphs003.htm
NamedQueryを作成し、キー javax.persistence.loadgraph
または javax.persistence.fetchgraph
でヒントを添付します。グラフで定義した関連エンティティを取得します。
&quot; loadgraph&quot;の違いの詳細を確認できます。および「fetchgraph」」ここ: JPAのエンティティグラフのFETCHとLOADの違いは何ですか