32

使用 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

但是,条件查询导致根表不必要地连接到相关实体表两次;一次用于获取,一次用于 where 谓词。生成的 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

唉,如果我只做 fetch,那么我没有表达式可以在 where 子句中使用。

我是否遗漏了什么,或者这是 Criteria API 的限制?如果是后者,这是否在 JPA 2.1 中得到纠正,或者是否有任何特定于供应商的增强功能?

否则,最好放弃编译时类型检查(我意识到我的示例不使用元模型)并使用动态 JPQL TypedQueries。

4

3 回答 3

38

而不是root.join(...)你可以使用root.fetch(...)which 返回Fetch<>对象。

Fetch<>是的后代Join<>但它可以以类似的方式使用。

你只需要转换Fetch<>它就Join<>可以适用于 EclipseLink 和 Hibernate

...
Join<MyEntity, RelatedEntity> join = (Join<MyEntity, RelatedEntity>)root.fetch("relatedEntity");
...
于 2013-06-25T20:48:41.387 回答
11

从 JPA 2.1 开始,您可以为此使用动态实体图。删除您的 fetch 并指定一个实体图,如下所示:

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);
于 2017-03-23T18:53:45.020 回答
1

在 EclipseLink 上使用root.fetch()将创建一个 SQL,INNER JOIN因为它有 3 种类型,默认为 INNER。

INNER,  LEFT,  RIGHT;

建议是使用 CreateQuery。

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

编辑:您可以像这样将根转换为 From:

From<?, ?> join = (From<?, ?>) root.fetch("relatedEntity");
于 2015-04-27T13:50:05.543 回答