Sti*_*nux 11 java mysql hibernate criteria-api jpa-2.0
我有多个通过JPA2 Criteria Query查询的实体.
我可以加入其中两个实体并立即获得结果:
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<LadungRgvorschlag> criteriaQuery = criteriaBuilder.createQuery(LadungRgvorschlag.class);
Root<LadungRgvorschlag> from = criteriaQuery.from(LadungRgvorschlag.class);
Join<Object, Object> ladung = from.join("ladung");
from.fetch("ladung", JoinType.INNER);
Run Code Online (Sandbox Code Playgroud)
然后我尝试加入另外一个表:
ladung.join("ladBerechnet");
ladung.fetch("ladBerechnet", JoinType.LEFT);
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=generatedAlias3,role=null,tableName=ladberechnet,tableAlias=ladberechn3_,origin=ladungen ladung1_,columns={ladung1_.id ,className=de.schuechen.beans.tms.master.LadBerechnet}}] [select generatedAlias0 from de.schuechen.beans.tms.master.LadungRgvorschlag as generatedAlias0 inner join generatedAlias0.ladung as generatedAlias1 inner join generatedAlias1.ladBerechnet as generatedAlias2 left join fetch generatedAlias1.ladBerechnet as generatedAlias3 inner join fetch generatedAlias0.ladung as generatedAlias4 where ( generatedAlias0.erledigt is null ) and ( generatedAlias0.belegart in (:param0, :param1) ) and ( generatedAlias1.fzadresse in (:param2, :param3) ) and ( generatedAlias1.zudatum<=:param4 ) and ( 1=1 ) order by generatedAlias0.belegart asc, generatedAlias1.fzadresse asc, generatedAlias1.zudatum asc, generatedAlias1.zulkw asc]
Run Code Online (Sandbox Code Playgroud)
我如何告诉JPA/Hibernate,它应该一次选择所有实体?
Arj*_*jms 11
使用JPA'JPA的一些方言',您可以链接连接提取,但我认为您不能/应该同时执行连接和连接提取.
举例来说,如果我们有一个Program具有一个一对多的关系的Reward,有一个关系到Duration,以下JPQL将获得与奖励和持续时间预取特定的实例:
SELECT DISTINCT
program
FROM
Program _program
LEFT JOIN FETCH
_program.rewards _reward
LEFT JOIN FETCH
_reward.duration _duration
WHERE
_program.id = :programId
}
Run Code Online (Sandbox Code Playgroud)
使用等效的Criteria代码:
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Program> criteriaQuery = criteriaBuilder.createQuery(Program.class);
Root<Program> root = criteriaQuery.from(Program.class);
Fetch<Program, Reward> reward = root.fetch("rewards", JoinType.LEFT);
Fetch<Reward, Duration> duration = reward.fetch("duration", JoinType.LEFT);
criteriaQuery.where(criteriaBuilder.equal(root.get("id"), programId));
TypedQuery<program> query = entityManager.createQuery(criteriaQuery);
return query.getSingleResult();
Run Code Online (Sandbox Code Playgroud)
请注意,此处不需要中间变量奖励和持续时间,但它们仅用于提供信息.root.fetch("rewards", JoinType.LEFT).fetch("duration", JoinType.LEFT)会产生同样的效果.
对于JPA来说,你不能在Criteria API查询中链接连接(从规范引用):
fetch方法引用的关联或属性必须从作为查询结果返回的实体或embeddable引用.提取连接具有与对应的内连接或外连接相同的连接语义,除了相关对象不是查询结果中的顶级对象,并且查询无法在其他位置引用.
JPQL查询也不支持它:
FETCH JOIN子句右侧引用的关联必须是从实体引用的关联或元素集合,或者是作为查询结果返回的可嵌入的集合.
不允许为FETCH JOIN子句右侧引用的对象指定标识变量,因此对隐式获取的实体或元素的引用不能出现在查询的其他位置.
使用HQL似乎是可能的:Hibernate文档 EclipseLink不提供这样的扩展,因此Hibernate接受以下查询的语法,但EclipseLink不接受:
SELECT a FROM A a LEFT JOIN FETCH a.bb b LEFT JOIN FETCH b.cc
Run Code Online (Sandbox Code Playgroud)
在EclipseLink中,可以通过查询提示完成相同的操作.