web-dev-qa-db-ja.com

JPA基準APIを使用して、フェッチ結合を実行して、結合を1つだけにすることはできますか?

JPA 2.0を使用します。デフォルト(明示的なフェッチなし)では、@OneToOne(fetch = FetchType.EAGER)フィールドは1 + Nクエリでフェッチされます。Nは、個別の関連エンティティとの関係を定義するエンティティを含む結果の数です。 Criteria APIを使用して、次のように回避しようとする場合があります。

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<MyEntity> query = builder.createQuery(MyEntity.class);
Root<MyEntity> root = query.from(MyEntity.class);
Join<MyEntity, RelatedEntity> join = root.join("relatedEntity");
root.fetch("relatedEntity");
query.select(root).where(builder.equals(join.get("id"), 3));

上記は理想的には以下と同等でなければなりません:

SELECT m FROM MyEntity m JOIN FETCH myEntity.relatedEntity r WHERE r.id = 3

ただし、基準クエリの結果、ルートテーブルが不必要に関連するエンティティテーブルに2回結合されます。フェッチ用に1回、where述語用に1回。結果のSQLは次のようになります。

SELECT myentity.id, myentity.attribute, relatedentity2.id, relatedentity2.attribute 
FROM my_entity myentity 
INNER JOIN related_entity relatedentity1 ON myentity.related_id = relatedentity1.id 
INNER JOIN related_entity relatedentity2 ON myentity.related_id = relatedentity2.id 
WHERE relatedentity1.id = 3

残念ながら、フェッチのみを行う場合、where句で使用する式はありません。

何か不足していますか、またはこれはCriteria APIの制限ですか?後者の場合、これはJPA 2.1で修正されていますか、またはベンダー固有の拡張機能はありますか?

そうでない場合は、コンパイル時の型チェックをあきらめ(この例ではメタモデルを使用しないことに気付きます)、動的なJPQL TypedQueriesを使用する方が良いようです。

22
Shaun

root.join(...)の代わりに、root.fetch(...)を使用して_Fetch<>_オブジェクトを返すことができます。

_Fetch<>_は_Join<>_の子孫です ただし、同様の方法で使用できます。

_Fetch<>_を_Join<>_にキャストするだけで、EclipseLinkおよびHibernateで動作するはずです。

_...
Join<MyEntity, RelatedEntity> join = (Join<MyEntity, RelatedEntity>)root.fetch("relatedEntity");
...
_
29
Ondrej Bozek

JPA 2.1以降では、動的なエンティティグラフを使用できます。フェッチを削除し、次のようにエンティティグラフを指定します。

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<MyEntity> query = builder.createQuery(MyEntity.class);
Root<MyEntity> root = query.from(MyEntity.class);
Join<MyEntity, RelatedEntity> join = root.join("relatedEntity");
query.select(root).where(builder.equal(join.get("id"), 3));
EntityGraph<MyEntity> fetchGraph = entityManager.createEntityGraph(MyEntity.class);
fetchGraph.addSubgraph("relatedEntity");
entityManager.createQuery(query).setHint("javax.persistence.loadgraph", fetchGraph);
6
Darren Reimer

EclipseLinkでroot.fetch()を使用すると、3つのタイプがあり、デフォルトはINNERであるため、INNER JOINでSQLが作成されます。

INNER,  LEFT,  RIGHT;

提案は、CreateQueryを使用することです。

TypedQuery<T> typedQuery = entityManager.createQuery(query);

編集:次のようにルートをキャストすることができます:

From<?, ?> join = (From<?, ?>) root.fetch("relatedEntity");
1
Fábio Almeida