代码之家  ›  专栏  ›  技术社区  ›  masber

如何在JPA条件中执行连接获取

  •  1
  • masber  · 技术社区  · 6 年前

    我正在尝试将下面的查询转换为条件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';
    

    问题: 当从两个表(eReturn和ProductItem)中提取字段时,如何告诉Hibernate只使用1个join来生成此查询?

    2 回复  |  直到 6 年前
        1
  •  3
  •   K.Nicholas    6 年前

    的确,这是个问题,但是您的答案显示了另外两个表,并且不是正确的答案。试试这个:

    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 答案再往下一点。

        2
  •  0
  •   masber    6 年前

    显然,强制转换是一种方法,但是我们需要考虑到.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=?