Java 在JPA critera查询中按聚合字段筛选

Java 在JPA critera查询中按聚合字段筛选,java,spring,jpa,spring-data-jpa,Java,Spring,Jpa,Spring Data Jpa,我在编写将按聚合排序的规范时遇到问题。 假设我有两个实体: @Entity public class Property { @Id @GeneratedValue private Long id; @OneToMany @Cascade(org.hibernate.annotations.CascadeType.ALL) private List<Feedback> ratings; } 我试图实现的是获得所有属性,平均评级高于给

我在编写将按聚合排序的
规范时遇到问题。
假设我有两个实体:

@Entity
public class Property {

    @Id
    @GeneratedValue
    private Long id;

    @OneToMany
    @Cascade(org.hibernate.annotations.CascadeType.ALL)
    private List<Feedback> ratings;
}
我试图实现的是获得所有
属性
,平均评级高于给定阈值。下面是我使用强大的谷歌时想到的:

private static Specification<Property> ratingsSpec(Double minRating) {
    return (root, query, criteriaBuilder) -> {
        ListJoin<Property, Feedback> feedbackJoin = root.join(Property_.ratings);
        return criteriaBuilder.greaterThanOrEqualTo(criteriaBuilder.avg(feedbackJoin.get(Feedback_.rating)), minRating);
    };
}
我复制错误完全是为了不让任何重要的事情发生,显然那里有比我上面提到的更多的字段

现在,我看到了查询的问题,条件肯定应该在
having
子句中,而不是
where
,我缺少
groupby
子句。但我如何做到这一点呢? 任何帮助都将不胜感激

奖金问题:
如何按相同的值排序?;)

实际上是通过查询实现的。我不确定这是否是最好的解决方案,所以如果有人有意见,我会洗耳恭听。以下是工作解决方案:

private static Specification<Property> ratingsSpec(Double minRating) {
        return (root, query, criteriaBuilder) -> {
            ListJoin<Property, Feedback> feedbackJoin = root.join(Property_.ratings);
            Expression<Double> avg = criteriaBuilder.avg(feedbackJoin.get(Feedback_.rating));
            return query.groupBy(root).having(criteriaBuilder.greaterThanOrEqualTo(avg, minRating)).getRestriction();
        };
    }
private static Specification ratingsSpec(双重额定值){
返回(根、查询、准则生成器)->{
ListJoin feedbackJoin=root.join(属性等级);
表达式avg=criteriaBuilder.avg(feedbackJoin.get(Feedback.rating));
返回query.groupBy(root).having(criteriaBuilder.greaterThanOrEqualTo(avg,minRating)).getRestriction();
};
}

规范旨在动态创建WHERE子句,如果您想创建任意查询,我建议您编写一个自定义方法。@Jenschauder感谢您的建议。我知道,很明显,我的案例可能看起来很荒谬,但这是为了简单。我实际上是在动态地使用它,基于过滤器对象创建它们。所有其他条件都很简单,where子句,这是我唯一有问题的条件。在这种情况下,您有什么建议?我将使用自定义方法实现。但是,既然你找到了解决方案,就没有真正的理由去改变它。
Invalid use of aggregate function "AVG(CAST(FEEDBACK2_.RATING AS DOUBLE))"; 
SQL statement:
select property0_.id as id1_1_, property0_.additional_info as addition2_1_, property0_.address_line1 as address_3_1_, property0_.address_line2 as address_4_1_, property0_.city as city5_1_, property0_.postcode as postcode6_1_, property0_.area_sqm as area_sqm7_1_, property0_.rooms as rooms8_1_, property0_.type as type9_1_, property0_.version as version10_1_ from property property0_ inner join property_ratings ratings1_ on property0_.id=ratings1_.property_id inner join feedback feedback2_ on ratings1_.ratings_id=feedback2_.id where 1=1 and avg(cast(feedback2_.rating as double))>=3.9 [90054-199]
private static Specification<Property> ratingsSpec(Double minRating) {
        return (root, query, criteriaBuilder) -> {
            ListJoin<Property, Feedback> feedbackJoin = root.join(Property_.ratings);
            Expression<Double> avg = criteriaBuilder.avg(feedbackJoin.get(Feedback_.rating));
            return query.groupBy(root).having(criteriaBuilder.greaterThanOrEqualTo(avg, minRating)).getRestriction();
        };
    }