单向一对多关系的条件查询
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
的引用,这意味着我们有一个单向的一对多关系。我需要通过 posId
和 supplierId
寻找 POS
。即查找指定supplierId
的供应商,然后在供应商的pos列表中查找具有指定posId的pos。如何为此编写条件查询?
我试过使用子查询。我的想法是创建一个子查询,该子查询将获取具有给定 supplierId
的 Supplier
的所有 POS
。然后主查询将在那些 POS
中搜索具有给定 posId
.
的 POS
问题是我无法编写查询来获取 Supplier
s 的 POS
s 列表。显然你不能写 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 对象。
所以,我有以下实体:
@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
的引用,这意味着我们有一个单向的一对多关系。我需要通过 posId
和 supplierId
寻找 POS
。即查找指定supplierId
的供应商,然后在供应商的pos列表中查找具有指定posId的pos。如何为此编写条件查询?
我试过使用子查询。我的想法是创建一个子查询,该子查询将获取具有给定 supplierId
的 Supplier
的所有 POS
。然后主查询将在那些 POS
中搜索具有给定 posId
.
POS
问题是我无法编写查询来获取 Supplier
s 的 POS
s 列表。显然你不能写 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 对象。