20

エンティティ オブジェクトを編集せずに単一のメソッドで 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();
}

このメソッド (またはクラス全体) で熱心なフェッチを使用するにはどうすればよいですか?

4

4 に答える 4

17

エンティティの関連付け (@OneToOne、@OneToMany、@ManyToOne) は遅延フェッチされていると思います (FetchType.Lazy)

次に、次の 2 つの方法が考えられます。

A. lazy の関連付けを取得する 2 つの jpa クエリ (hibernate のデフォルトの方法) と、明示的に関連付けの熱心な読み込みを強制する 2 つ目のクエリ (クエリの「fetch」キーワードを参照) を記述します。

        クエリ q = HibernateUtil.getSessionFactory().getCurrentSession()
                .createQuery("カテゴリから c を 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);
于 2009-06-24T18:59:05.210 に答える
9

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>
于 2009-06-30T03:49:18.770 に答える
1

誰も 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

于 2014-05-20T09:07:43.843 に答える