单向一对多关系的条件查询

Criteria query for unidirectional one-to-many relationship

所以,我有以下实体:

@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的引用,这意味着我们有一个单向的一对多关系。我需要通过 posIdsupplierId 寻找 POS。即查找指定supplierId的供应商,然后在供应商的pos列表中查找具有指定posId的pos。如何为此编写条件查询?

我试过使用子查询。我的想法是创建一个子查询,该子查询将获取具有给定 supplierIdSupplier 的所有 POS。然后主查询将在那些 POS 中搜索具有给定 posId.

POS

问题是我无法编写查询来获取 Suppliers 的 POSs 列表。显然你不能写 List<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>> 的编译错误。而且我无法更改子查询的类型,因为 Java 不允许通用 class 文字 (List<POS>.class).

有什么想法吗?

您可以使用子查询来做到这一点。 SQL相当于jpql"select p from POS p where p.id in (select sp.id from Supplier s join s.posList sp where s.id = :supplierId)"

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

终于找到答案了,就用两个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);

我发现没有子查询的非常简单的解决方案。从Suppler开始,通过posList加入POS,然后'select' 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->M table 通过两个内部连接生成了很好的查询,这与手动编写的代码非常相似;-)。 接受的答案是我猜错了,因为它跳过了 "posList" 关系。它将 select 个与指定供应商无关的 POS 对象。