按 MAX(childitem.property) 对 JPA CriteriaQuery 的排序结果

Posted

技术标签:

【中文标题】按 MAX(childitem.property) 对 JPA CriteriaQuery 的排序结果【英文标题】:Ordering results of a JPA CriteriaQuery by MAX(childitem.property) 【发布时间】:2014-01-08 15:46:55 【问题描述】:

我试图找到一种优雅的方式,使用子对象集合的第一个属性而不是对象本身对 JPA 条件查询的结果进行排序。例如:

@Entity
class Parent 
  protected Set<Child> children;


@Entity
class Child 
  protected Date timestamp;

父母可以有多个孩子,每个孩子都有不同的时间戳

我希望能够添加到现有的 JPA CriteriaQuery/TypedQuery,以便按 MAX(child.timestamp) 对父对象列表进行排序,因此具有最新子时间戳的父对象首先出现。

我的通用标准构建器实现是这样的:

CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<T> criteriaQuery = criteriaBuilder.createQuery(daoClass);
Root<T> queryRoot = criteriaQuery.from(daoClass);

// add wheres
Predicate filters = createPredicate(criteriaQuery, queryRoot, criteriaBuilder);
// filters = criteriaBuilder.and( /* lots of Predicate filter objects */ );
criteriaQuery.where(filters);

// add sorts
criteriaQuery.orderBy(createOrders(queryRoot, criteriaBuilder));

// <-- Ideally somewhere here add the new ordering

TypedQuery<T> typedQuery = em.createQuery(criteriaQuery);

希望有一个不会破坏它太多的解决方案..

感谢您的帮助。

编辑:查询中收集的父数据是分页的,因此我无法对查询结果进行排序。它必须是我构造的 JPA 查询的一部分。

【问题讨论】:

【参考方案1】:

你不能这样做

@Entity
class Parent 
  @OrderBy("timestamp DESC")
  protected Set<Child> children;

【讨论】:

这只会按单个父对象的时间戳对子对象进行排序。我想要的是 List 的顺序是最新的子时间戳。示例:父 A 的 Child1.timestamp 为上午 10 点,Child2.timestamp 为上午 11 点。家长 B 的 Child3.timestamp 为上午 9 点,Child4.timestamp 为下午 4 点。家长 C 的 Child5.timestamp 为 12pm。我想要一个 CriteriaQuery 配置,它将按 [Parent B, Parent C, Parent A] 的顺序返回 List【参考方案2】:

我也遇到了同样的情况。

见JPA CriteriaQuery Order By Latest Child Property

对于您的具体情况,诀窍是不要在按部分排序之前添加过滤器。 Criteria API 稍后会按正确的顺序放入。

所以它应该是这样的:

CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<T> criteriaQuery = criteriaBuilder.createQuery(daoClass);
Root<T> queryRoot = criteriaQuery.from(daoClass);

// get filters
Predicate filters = createPredicate(criteriaQuery, queryRoot, criteriaBuilder);
// filters = criteriaBuilder.and( /* lots of Predicate filter objects */ );
//This has to be a Boolean object (not primitive) so that it passes the reference to the object to your createOrders method and not the value.
Boolean filtersAdded = Boolean.FALSE;

// add sorts - send filters as a parameter
criteriaQuery.orderBy(createOrders(filters, filtersAdded, queryRoot, criteriaBuilder));

if (Boolean.FALSE.equals(filtersAdded)) 
    criteriaQuery.where(filters);


TypedQuery<T> typedQuery = em.createQuery(criteriaQuery);

createOrders 方法中,如果您必须添加子查询 where 条件 (JPA CriteriaQuery Order By Latest Child Property),请同时添加过滤器。像这样:

criteriaQuery.where(subQueryCondition, filters));
filtersAdded = Boolean.TRUE;

【讨论】:

以上是关于按 MAX(childitem.property) 对 JPA CriteriaQuery 的排序结果的主要内容,如果未能解决你的问题,请参考以下文章

如何按 MAX(日期)选择?

按 Max 分组

SQL - 使用 MAX 函数按问题分组两列

Sql Server - 查询帮助(按 MAX 分组)

Spark.sql 按 MAX 过滤行

LinQ to Entities,Max Date字段,按什么分组