标准 API 按嵌套聚合排序 属性
Criteria API Ordering by nested aggregated property
如何通过聚合嵌套 属性 实现对象排序?
我有一个 Photographer 实体,其中有很多 PhotographerPrice 实体(一对多),BigDecimal 属性 称为 pricePerHour。当我检索摄影师时,我想按他们所拥有的最低价格对他们进行排序。
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
我尝试对 PhotographerPrice 进行子查询,然后在根目录中排序
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 来实现它?也许还有另一种工具可以更方便地从数据库中过滤实体?我有很多用于过滤和排序的不同参数,这些参数与嵌套属性有关,有时甚至与嵌套在嵌套 属性.
中有关
我找到的唯一解决方法:
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));
但我不确定分组依据。有没有可能稍后出现一些故障排除?
我发现的方法适用于我的案例
使用 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));
}
如何通过聚合嵌套 属性 实现对象排序? 我有一个 Photographer 实体,其中有很多 PhotographerPrice 实体(一对多),BigDecimal 属性 称为 pricePerHour。当我检索摄影师时,我想按他们所拥有的最低价格对他们进行排序。
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
我尝试对 PhotographerPrice 进行子查询,然后在根目录中排序
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 来实现它?也许还有另一种工具可以更方便地从数据库中过滤实体?我有很多用于过滤和排序的不同参数,这些参数与嵌套属性有关,有时甚至与嵌套在嵌套 属性.
中有关我找到的唯一解决方法:
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));
但我不确定分组依据。有没有可能稍后出现一些故障排除?
我发现的方法适用于我的案例
使用 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));
}