Spring JPA 3.x JPQL group by 实体必须出现在 GROUP BY 子句中

Gau*_* T. 5 java spring hibernate jpa spring-data-jpa

我发现了一个奇怪的行为,我想知道我是否滥用了 JPA 或者它是否是 Spring 回归。

这是我的实体:

@Entity
public class Brand {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(nullable = false)
    @EqualsAndHashCode.Include
    @Schema(description = "Brand's id", example = "1")
    private Long id;
    // ...
}

@Entity
public class Product {
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "product_brands", joinColumns = @JoinColumn(name = "product_id"),
        inverseJoinColumns = @JoinColumn(name = "brands_id"))
    private List<Brand> brands;
    // ...
}
Run Code Online (Sandbox Code Playgroud)

我有这个请求:

@Query("select new com.mypackage.Statistic(br, count(p)) " +
        "from Lot l join l.products p join p.brands br " +
        "group by br " +
        "order by count(p) desc")
List<Statistic<Brand>> groupByProductBrand();
Run Code Online (Sandbox Code Playgroud)

这在 Spring Boot 2.5.4 中工作正常,然后我更新到版本 3.1.6,现在出现此错误:

ERROR: column "b1_1.id" must appear in the GROUP BY clause or be used in an aggregate function<EOL>
Run Code Online (Sandbox Code Playgroud)

执行的请求是:

select b1_1.id, ..., count(p1_0.products_id) 
from lot l1_0
join (lot_products p1_0 join product p1_1 on p1_1.id=p1_0.products_id) on l1_0.id=p1_0.lot_id 
join (product_brands b1_0 join brand b1_1 on b1_1.id=b1_0.brands_id) on p1_1.id=b1_0.product_id 
group by b1_0.brands_id 
order by count(p1_0.products_id) desc offset;
Run Code Online (Sandbox Code Playgroud)

经过一些测试,在 select 和 group by 子句中给出所有列名后,看起来 select 中的 br.id 取自品牌表 (b1_1),但 group by 中的 br.id 取自关联表 (b1_0) )。值显然是相同的,但在这个用例中,sql 查询失败。

Eug*_*mov 0

我想您必须在子句中使用单值路径表达式(或标识变量)group by,可以使用关键字获取该IN表达式。

尝试以下两个查询(不确定哪个在语法上是正确的,尽管我相信它应该是第一个或两个):

"select new com.mypackage.Statistic(br, count(p)) " +
    "from Lot l join l.products p, IN(p.brands) br " +
    "group by br " +
    "order by count(p) desc"
Run Code Online (Sandbox Code Playgroud)

或者

"select new com.mypackage.Statistic(br.brand, count(p)) " +
    "from Lot l join l.products p, IN(p.brands) br " +
    "group by br.brand " +
    "order by count(p) desc"
Run Code Online (Sandbox Code Playgroud)