Spring Boot 3.0集成JPA 3.1查询实例化失败问题求助
问题:Spring Boot 3.0升级后JPQL构造器传实体报错
升级至Spring Boot 3.0后,以下JPQL查询无法正常运行,报错参数类型不匹配,想确认是否不再支持在JPQL构造器中传入完整的数据库实体对象(如示例中的op)?
相关代码
Repository查询方法
@Query(""" select new com.example.OrderProductWithAmount( op, sum(op.amount), sum(op.paidAmount) ) from OrderProduct op join op.order o join op.product p join o.table t where t.id = :tableId group by p.id """) fun getAllSummarizedByTableId(@Param("tableId") tableId: Long): List<OrderProductWithAmount>
数据类与实体类
data class OrderProductWithAmount( val orderProduct: OrderProduct, val amount: Int, val paidAmount: Int ) { constructor( orderProduct: OrderProduct, amount: Long, paidAmount: Long ) : this( orderProduct, amount.toInt(), paidAmount.toInt() ) } @Entity @jakarta.persistence.Table(name = "order_product") data class OrderProduct( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = -1, @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "order_id", nullable = false) var order: Order, @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "product_id", nullable = false) var product: Product, @Column(name = "amount", nullable = false) var amount: Int, @Column(name = "paid_amount", nullable = false) var paidAmount: Int = 0, )
报错日志
Error performing dynamic instantiation : com.example.OrderProductWithAmount org.springframework.orm.jpa.JpaSystemException: Error performing dynamic instantiation : com.example.OrderProductWithAmount Caused by: org.hibernate.query.sqm.sql.internal.InstantiationException: Error performing dynamic instantiation : com.example.OrderProductWithAmount at app//org.hibernate.sql.results.graph.instantiation.internal.DynamicInstantiationAssemblerConstructorImpl.assemble(DynamicInstantiationAssemblerConstructorImpl.java:58) ... Caused by: java.lang.IllegalArgumentException: argument type mismatch ...
解答
不是Spring Boot 3.0/Hibernate 6.x不再支持在JPQL构造器中传入实体对象,问题出在你的分组查询逻辑上:
你在JPQL中使用了group by p.id,这意味着查询会按Product的ID进行分组,每个分组对应多条OrderProduct记录。此时Hibernate无法将分组后的结果映射为单个OrderProduct实体——因为分组结果不是某一条具体的OrderProduct行,而是一组记录的聚合,这直接导致了构造器参数类型不匹配的报错。
解决方案
方案1:调整构造器参数,传入实体的具体字段(推荐)
既然是按产品分组做聚合,应该只传入分组相关的字段(比如产品ID、名称),而非完整的OrderProduct实体。修改后的JPQL和数据类如下:
// 修改后的Repository查询 @Query(""" select new com.example.OrderProductWithAmount( p.id, p.name, sum(op.amount), sum(op.paidAmount) ) from OrderProduct op join op.order o join op.product p join o.table t where t.id = :tableId group by p.id, p.name """) fun getAllSummarizedByTableId(@Param("tableId") tableId: Long): List<OrderProductWithAmount> // 修改后的数据类 data class OrderProductWithAmount( val productId: Long, val productName: String, val amount: Int, val paidAmount: Int ) { constructor( productId: Long, productName: String, amount: Long, paidAmount: Long ) : this( productId, productName, amount.toInt(), paidAmount.toInt() ) }
方案2:调整分组逻辑(仅在特殊场景下使用)
如果确实需要关联OrderProduct的信息,必须将OrderProduct的所有非聚合字段加入group by子句,但这会让分组粒度变细,失去按产品聚合的意义,通常不推荐这种写法。
补充说明
Spring Boot 3.0对应的Hibernate版本是6.x,相比旧版本,它对JPQL的语法检查和分组查询的映射逻辑更加严格。旧版本可能允许这种不规范的分组写法,但新版本会直接抛出类型不匹配的错误,本质是帮你规避了逻辑上的不合理性。
内容的提问来源于stack exchange,提问作者kaulex
相关产品推荐
相关产品推荐

