使用JPA 2.0。默认情况下(没有显式的fetch设置),@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
然而,基于条件的查询会导致根表与相关实体表不必要地重复连接两次;一次用于提取数据(fetch),一次用于where谓词。生成的SQL大致如下:
然而,对于根表和关联实体表的条件查询结果,存在无需重复连接的情况;一次用于获取(fetch),一次用于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。
Join<MyEntity, RelatedEntity>
会导致我的IDE标记该语句为警告。 我发现将其转换为org.hibernate.ejb.criteria.path.SingularAttributeJoin<MyEntity, RelatedEntity>
可以消除警告。调用root.fetch
执行以下操作:FetchParent#fetch(String)
AbstractFromImpl#fetch(String) [FetchParent的实现]
AbstractFromImpl#fetch(SingularAttribute, JoinType)
AbstractFromImpl#constructJoin(SingularAttribute,JoinType) [返回SingularAttributeJoin]
- Chris PartonFetch
转换为Join
,但不能执行fetch.on(...)
,因为它会说“无法与获取联接一起使用with子句-请使用过滤器”。我需要添加一个额外的条件来加入(除了ID之外)。当我只是做root.join(...)
,然后join.on(...)
时,正确的连接被生成,但它们没有获取已连接的数据(在选择中未列出字段)。也许你知道一些解决方法? - Shadov(Join)
,让你的集成开发环境感到愉快! - raghavsood33