Criteria查询单向一对多关系

时间:2015-01-14 09:07:38

标签: hibernate one-to-many criteria-api

所以,我有以下实体:

@Entity
public class Supplier {
    @Column(name = "SUPPLIERID")
    private BigInteger supplierId;

    @OneToMany
    @JoinColumn(name = "ID_SUPP", foreignKey = @ForeignKey(name = "fk_POIS_SUPP"))
    private List<POS> posList;

    ...
}

@Entity
public class POS {
    @Column(name = "POSID")
    private BigInteger posId
}

因此,POS没有对Supplier的引用,这意味着我们具有单向一对多关系。我需要POSposId寻找supplierId。也就是说,找到具有指定supplierId的供应商,然后在供应商的具有指定posId的pos列表中找到pos。如何为此编写条件查询?

我尝试使用子查询。我的想法是创建一个子查询,该子查询将使用给定的POS获取Supplier的所有supplierId个。然后主要查询会在POSPOS内搜索给定posId的{​​{1}}。

问题是我无法编写一个可以获取Supplier POSList<POS>列表的查询。显然,您无法编写CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery<POS> outerQuery = cb.createQuery(POS.class); Root<POS> outerQueryRoot = outerQuery.from(POS.class); Subquery<POS> subquery = outerQuery.subquery(POS.class); Root<Supplier> subqueryRoot = subquery.from(Supplier.class); subquery.where(cb.equal(subqueryRoot.get(Supplier_.supplierId), supplierId)); subquery.select(subqueryRoot.get(Supplier_.posList); 类型的查询:

Expression<POS> does not match Expression<List<POS>>

在最后一行,我收到List<POS>.class的编译错误。而且我无法更改子查询的类型,因为Java不允许使用泛型类文字({{1}})。

有什么想法吗?

3 个答案:

答案 0 :(得分:2)

我终于找到了答案,只需使用两个roots

    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<POS> cq = cb.createQuery(POS.class);

    Root<POS> posRoot = cq.from(POS.class);
    Root<Supplier> supplierRoot = cq.from(Supplier.class);

    cq.where(cb.and(
                    cb.equal(supplierRoot.get(Supplier_.suppliertId), supplierId),
                    cb.equal(posRoot.get(POS_.posId), posId)));
    cq.select(posRoot);

答案 1 :(得分:2)

我找到了没有子查询的非常简单的解决方案。从Suppler开始,通过posList加入POS,然后'选择'POS。

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<POS> query = cb.createQuery(POS.class);

Root<Supplier> supplierRoot = query.from(Supplier.class);
ListJoin<Supplier, POS> posList = supplierRoot.joinList(Supplier_.posList);
query
    .select(posList)
    .where(
        cb.equal(supplierRoot.get(Supplier_.suppliertId), supplierId),
        cb.equal(posList.get(POS_.posId), posId)
    );

使用Hibernate 5.2.11,它通过N&gt; M表生成了两个内部连接的良好查询,非常类似于手动编写的代码;-)。 接受的答案是我错了,因为它跳过“posList”关系。它将选择与指定供应商无关的POS对象。

答案 2 :(得分:0)

您可以使用子查询执行此操作。 SQL相当于jpql“从POS p中选择p,其中p.id in(从供应商s中选择sp.id加入s.posList sp,其中s.id =:supplierId)”

请参阅JPA2 Criteria-API: select... in (select from where)