考虑实体A
与实体@OneToMany
的单向 B
关系。 B在持久化时设置了持久时间戳字段,之后从未更改过。
如何为添加到集合中的最后一个({第一个)A
的每个B
创建一个条件(元组)查询?
到目前为止,这是我的看法:
// Root query
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> q = cb.createTupleQuery();
Root<A> root = q.from(A.class);
Join<A, B> bItem = root.join("listOfB");
// Subquery
Subquery<Date> sq = q.subquery(Date.class);
Join<A, B> sqBItem = sq.correlate(bItem);
Expression<Date> sqBItemCreatedOn = sqBItem.get("createdOn"); // <-- TS on sqBItem
sq.select(cb.greatest(sqBItemCreatedOn)).groupBy(root);
// Back to the root query
Expression<Date> bItemCreatedOn = bItem.get("createdOn"); // <-- TS on bItem
q.multiselect(root, bItem).where(cb.equal(bItemCreatedOn, sq));
em.createQuery(q).getResultList(); // <-- fails
我也试过
q.multiselect(root, cntItem).where(cb.in(cntCreatedOn).value(sq));
但无济于事。
请注意,此阶段的关系是单向,所以我想知道子查询部分是否正常工作。通过将关系设置为双向,我想我可以在B
上查询A
并在{{1}}上进行分组,但我无法控制域模型。
答案 0 :(得分:1)
这是我的尝试(没有子查询):
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> q = cb.createTupleQuery();
Root<A> root = q.from(A.class);
Join<A, B> bItem = root.join("listOfB");
q.multiselect(
root.alias("A"),
cb.greatest(bItem.<Date>get("createdOn")).alias("TS")); //MAX
// cb.least(bItem.<Date>get("createdOn")).alias("TS")); //MIN
q.orderBy(cb.asc(root));
q.groupBy(root);
List<Tuple> tuples = em.createQuery(q).getResultList()
for (Tuple array : result) {
System.out.println(array.get("A").toString() + ":\t" + array.get("TS"));
}
从JPQL角度来看,这可能如下所示:
SELECT root, MAX(b.createdOn)
FROM A root JOIN root.listOfB bItem
GROUP BY root
ORDER BY root;