エンティティオブジェクトを編集せずに、単一のメソッドで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クエリを記述します。1つは遅延の関連付けをフェッチし(これは休止状態のデフォルトの方法です)、もう1つは関連付けの積極的な読み込みを明示的に強制するクエリです(クエリの「fetch」キーワードを参照)。
クエリ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)を使用して、エンティティを取得した後(Finderなどを介して)エンティティの遅延関係を強制的にロードします。
ErrorCode lazyCode = findErrorCodeById(1); //熱心な負荷の関連付け Hibernate.initialize(lazyCode);
JPAでは、フェッチモードは、アノテーションまたはxmlマッピングファイルのいずれかを介して、各永続属性で指定されます。
したがって、JPAベンダーに依存しない目標を達成する方法は、DAOレイヤーごとに個別のマッピングファイルを用意することです。残念ながら、これにはマッピングファイルごとに個別のPersistenceUnitが必要になりますが、少なくとも同じエンティティクラスと同じJPQLクエリを共有できます。
コードスケルトンが続きます。
永続性.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レイヤーで適切な永続性ユニット用の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だけです。より現実的なシナリオを反映するようにフィールド名を変更しました(デフォルトでは、コレクションとブロブのみが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>
JPA2ではEntityGraphsを使用します。これにより、関連するエンティティを定義できます。取得したい:
https://docs.Oracle.com/javaee/7/tutorial/persistence-entitygraphs002.htmhttps://docs.Oracle.com/javaee/7/tutorial/persistence- entitygraphs003.htm
行ったようにNamedQueryを作成し、キーjavax.persistence.loadgraph
またはjavax.persistence.fetchgraph
を使用してヒントを添付します。グラフで定義した関連エンティティを取得します。
「loadgraph」と「fetchgraph」の違いの詳細については、こちらをご覧ください: JPAのエンティティグラフのFETCHとLOADの違いは何ですか?
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