Hibernate使用Pageable排序无法解析entityName属性且结果映射失败
解决方案
1. 排序字段无法解析报错问题
报错原因是Pageable默认排序会校验查询根实体(即from后的McConsumerEntity/EbAccountConsumerEntity/McEntity)的属性,而amount、entityName是你自定义的查询别名,不属于根实体的原生字段,因此Hibernate找不到对应属性抛出异常。
可选解决方案:
- 方案1:将查询改为原生SQL模式,在
@Query注解中添加nativeQuery = true,此时Pageable排序会直接使用指定的别名作为SQL排序字段,无需校验根实体属性。 - 方案2:如果保留JPQL查询,使用
JpaSort.unsafe构造排序参数,跳过实体属性校验,示例:
// 按entityName升序示例 Sort sort = JpaSort.unsafe(Sort.Direction.ASC, "entityName"); Pageable pageable = PageRequest.of(pageNum, pageSize, sort);
2. 查询结果自动映射问题
默认情况下自定义聚合查询返回的字段列表会被封装为Object[]数组,不会自动映射到自定义实体类,可通过以下两种方案实现自动映射:
方案1:JPQL构造器表达式
第一步:给McConsumerBalanceEntityGenerated添加全参数构造方法,参数顺序、类型与查询select后的字段完全匹配:
public McConsumerBalanceEntityGenerated(Long id, String firstName, String lastName, BigDecimal amount, Long entityId, String entityName) { this.id = id; this.firstName = firstName; this.lastName = lastName; this.amount = amount; this.entityId = entityId; this.entityName = entityName; } // 保留无参构造方法 public McConsumerBalanceEntityGenerated() { }
第二步:修改@Query的select部分,使用构造器表达式指定返回类型:
@Query( value = "select new 替换为你实体类的全限定包名.McConsumerBalanceEntityGenerated(csr.id, csr.firstName, csr.lastName, " + "sum (case " + "when acs.type = 'PAYMENT' then acs.amount " + "else -acs.amount " + "end) as amount, " + "me.id as entityId, " + "me.name as entityName " + "from McConsumerEntity csr, EbAccountConsumerEntity acs, McEntity me " + "where csr.idMcEntity in :childEntityIds " + "and csr.idMcEntity = me.id " + "and csr.id = acs.idMcConsumer " + "and amount > 0 " + "group by csr.id, me.id, me.name " )
修改后Repository层方法直接返回Page<McConsumerBalanceEntityGenerated>即可实现自动映射。
方案2:SqlResultSetMapping映射(适配原生SQL场景)
第一步:在McConsumerBalanceEntityGenerated类上添加结果集映射注解:
@SqlResultSetMapping( name = "McConsumerBalanceMapping", classes = @ConstructorResult( targetClass = McConsumerBalanceEntityGenerated.class, columns = { @ColumnResult(name = "id", type = Long.class), @ColumnResult(name = "firstName", type = String.class), @ColumnResult(name = "lastName", type = String.class), @ColumnResult(name = "amount", type = BigDecimal.class), @ColumnResult(name = "entityId", type = Long.class), @ColumnResult(name = "entityName", type = String.class) } ) ) @Entity public class McConsumerBalanceEntityGenerated implements Serializable { // 原有代码保持不变 }
第二步:如果使用原生SQL查询,在@Query注解中指定映射规则:
@Query( value = "原生SQL语句", nativeQuery = true, resultSetMapping = "McConsumerBalanceMapping" )
注意:如果使用PostgreSQL原生SQL,需注意字段别名大小写敏感问题,别名需与
@ColumnResult中配置的name完全一致。
内容的提问来源于stack exchange,提问作者Vladimir Cvetkovic
相关产品推荐
相关产品推荐

