如何在 jpa 标准中进行 JOIN FETCH

问题描述 投票:0回答:3

我正在尝试将下面的查询转换为条件 api。

SELECT er from ereturn er JOIN FETCH product_item pi ON pi.ereturn_id = er.id WHERE pi.status = "RECEIVED"

对于这样的事情:

CriteriaBuilder builder = em.getCriteriaBuilder();

CriteriaQuery<Ereturn> criteria = builder.createQuery( Ereturn.class );

Root<Ereturn> er = criteria.from(Ereturn.class);
Join<Ereturn, ProductItem> productItemJoin = er.join("productItems", JoinType.LEFT);
Fetch<Ereturn, ProductItem> productItemFetch = er.fetch("productItems", JoinType.LEFT);

List<Predicate> predicates = new ArrayList<>();

predicates.add(builder.equal( productItemJoin.get( "status" ), "RECEIVED"));

criteria.where(
        builder.and(predicates.toArray(new Predicate[predicates.size()]))
);

List<Ereturn> ers = em.createQuery( criteria )
    .getResultList();

问题是 hibernate 生成了这个查询:

select
ereturn0_.id as ...
...
productite6_.id as ...
...
from
ereturn ereturn0_ 
join
product_item productite1_ 
on ereturn0_.id = productite1_.ereturn 
join
product_item productite6_ 
on ereturn0_.id = productite6_.ereturn
where
productite1_.status='RECEIVED';

问题:我如何告诉hibernate在从两个表(ereturn和productItem)获取字段时仅使用1个连接生成此查询?

hibernate jpa join hibernate-criteria
3个回答
23
投票

确实这是一个问题,但您的答案显示了两个附加表格,并且不是正确的答案。试试这个:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Ereturn> q = cb.createQuery(Ereturn.class);
Root<Ereturn> r = q.from(Ereturn.class);
r.fetch("productItem", JoinType.LEFT);
// here join with the root instead of the fetch
// casting the fetch to the join could cause portability problems
// plus, not nice
q.where(cb.equal(r.get("productItem").get("status"), "received"));
Ereturn ereturn= em.createQuery(q).getSingleResult();

这给出了

select ereturn0_.id as id1_0_0_, productite1_.id as id1_1_1_, ereturn0_.parentEreturn_id as parentCo2_0_0_, ereturn0_.productItem_id as productI3_0_0_, productite1_.status as status2_1_1_ 
from Ereturn ereturn0_ 
left outer join ProductItem productite1_ on ereturn0_.productItem_id=productite1_.id 
where productite1_.status=?

请参阅答案中稍远一点的JPA 2 Criteria Fetch Path Navigation


10
投票

显然,强制转换是正确的方法,但是我们需要考虑到 .fetch()/.join() 是通用方法,因此强制转换有点不同

选项1

Fetch<Ereturn, ProductItem> productItemFetch = er.fetch("productItems", JoinType.LEFT);
Join<Ereturn, ProductItem> productItemJoin = (Join<Ereturn, ProductItem>) productItemFetch;

选项2

Join<Ereturn, ProductItem> productItemJoin = (Join<Ereturn, ProductItem>) er.<Ereturn, ProductItem>fetch("productItems", JoinType.LEFT)

现在查询与我正在寻找的内容是正确的:

select
...
from
    ereturn ereturn0_ 
left outer join
    product_item productite5_ 
        on ereturn0_.id=productite5_.ereturn 
where
    and productite5_.status=?

0
投票

从 RawMaterial 中选择不同的 f f JOIN FETCH f.fieldArea fa JOIN FETCH fa.stores WHERE f.id = :rawId 如何处理这种类型的嵌套连接获取...RawMaterial 类具有 onetoMany fieldArea 作为 Eager,而 FieldArea 类具有 oneToMany 商店作为 Lazy..我尝试使用filedArea 和 Stores 获取 RawMaterial..如何执行此操作..我尝试这个方式..” 列表谓词 = new ArrayList<>();

    if (id != null) {
        predicates.add(criteriaBuilder.equal(root.get("id"), rawId));
    }

    Fetch<RawMaterial, FieldArea> pagesFetch = root.fetch("fieldArea", JoinType.LEFT);
    pagesFetch.fetch("stores", JoinType.LEFT);

    criteriaQuery.distinct(true);
    return criteriaBuilder.and(predicates.toArray(new Predicate[0]));" i got only Rawmaterial with fieldAreas not stores...
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.