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レイヤーに適切な永続性ユニット用の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>