如何在一个查询中获取所有数据

2022-09-04 19:41:21

我有多个实体通过 JPA2 条件查询进行查询。

我能够加入其中两个实体并立即获得结果:

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);

然后我尝试像这样加入一个额外的表:

ladung.join("ladBerechnet");
ladung.fetch("ladBerechnet", JoinType.LEFT);

我得到以下错误:

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]

我怎么能告诉JPA / Hibernate,它应该一次选择所有实体?


答案 1

使用JPA“JPA的一些方言”,你可以链接联接提取,但我不认为你可以/应该同时做连接和连接提取。

例如,如果我们有一个与 a 有一对多关系的 a,而 a 与 a 有关系,则以下 JPQL 将获得一个特定的实例,其中预取了奖励和持续时间:ProgramRewardDuration

SELECT DISTINCT
    program
FROM
    Program _program
        LEFT JOIN FETCH
    _program.rewards _reward
        LEFT JOIN FETCH
    _reward.duration _duration
WHERE
    _program.id = :programId

}

使用等效的标准代码:

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();

请注意,这里不需要中间变量奖励和持续时间,但它们仅用于提供信息。 将具有相同的效果。root.fetch("rewards", JoinType.LEFT).fetch("duration", JoinType.LEFT)


答案 2

对于JPA,您无法在标准API查询中链接联接提取(引用自规范):

fetch 方法引用的关联或属性必须从作为查询结果返回的实体或可嵌入项中引用。提取联接与相应的内联接或外联接具有相同的联接语义,只是相关对象不是查询结果中的顶级对象,并且查询无法在其他位置引用。

而且在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

在EclipseLink中,也可以通过查询提示来完成相同的操作。


推荐