使用Criteria Query选择OneToMany关系的最后一个(或第一个)插入元素?

时间:2013-12-12 08:34:06

标签: java jpa jpa-2.0 criteria-api

考虑实体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}}上进行分组,但我无法控制域模型。

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;