【问题标题】:Criteria API Ordering by nested aggregated propertyCriteria API 按嵌套聚合属性排序
【发布时间】:2020-09-02 13:08:36
【问题描述】:

如何通过聚合嵌套属性实现排序对象? 我有一个摄影师实体,其中一个有很多带有名为 pricePerHour 的 BigDecimal 属性的摄影师价格实体(一对多)。当我检索摄影师时,我想按照他们的最低价格对他们进行排序。

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Photographer> cq = cb.createQuery(Photographer.class);
Root<Photographer> root = cq.from(Photographer.class);
List<Predicate> predicates = new ArrayList<>(); // I have a lot of predicates which set if data was present by client

我尝试对摄影师价格进行子查询,然后在根目录中进行排序

Subquery<BigDecimal> subquery = cq.subquery(BigDecimal.class);
Root<PhotographerPrice> from = subquery.from(PhotographerPrice.class);
Predicate and = cb.and(
        cb.equal(root.get(Photographer_.id), from.get(PhotographerPrice_.photographer).get(Photographer_.id)),
        cb.isNotNull(from.get(PhotographerPrice_.pricePerHour))
);
subquery.correlate(root);
subquery.where(and);
subquery.select(cb.min(from.get(PhotographerPrice_.pricePerHour)));
subquery.groupBy(from.get(PhotographerPrice_.photographer).get(Photographer_.id));

...

cq.orderBy(cb.asc(subquery));

但是,我意识到,不允许在 order by 子句中使用子查询。

那么,我如何使用 Criteria API 实现这样的功能:

select *
  from photographer p
  order by (
    select min(price_per_hour) minPrice
      from photographer_price pp
      where p.id = pp.photographer_id
        and pp.photo_per_hour is not null
      group by photographer_id
    );

当我尝试使用 Join 方法实现它时,我的结果列表中有重复项。

是否可以使用 Criteria API 来实现它?也许还有另一种工具可以更方便地过滤来自 DB 的实体?我有很多不同的参数用于过滤和排序,这些参数与嵌套属性有关,有时甚至与嵌套在嵌套属性中有关。

我找到解决它的唯一方法:

ListJoin<Photographer, PhotographerPrice> join = root.join(Photographer_.photographerPrices);
Expression<BigDecimal> min = cb.min(join.get(PhotographerPrice_.pricePerHour));
cq.orderBy(cb.desc(min));
cq.groupBy(root.get(Photographer_.id));

但我不确定分组依据。以后会不会出现一些故障排除?

【问题讨论】:

    标签: java spring hibernate spring-data-jpa criteria-api


    【解决方案1】:

    我发现适用于我的方法

    使用 Min 聚合函数左连接到PhotographerPrice,然后根据此聚合的结果进行排序:

    ListJoin<Photographer, PhotographerPrice> photographerPriceJoin = root.join(Photographer_.photographerPrices);
    Expression<BigDecimal> min = cb.min(photographerPriceJoin.get(PhotographerPrice_.pricePerHour));
    if (photographerCatalogFilter.getDirection().isDescending()) {
        orderList.add(cb.desc(min));
    } else {
        orderList.add(cb.asc(min));
    }
    

    【讨论】:

      猜你喜欢
      • 2015-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-13
      • 1970-01-01
      • 2017-07-04
      • 2017-06-08
      • 1970-01-01
      相关资源
      最近更新 更多