Spring Boot 3升级后使用SUM SQL函数触发ConverterNotFoundException求助
解决Spring Boot 3中SUM聚合函数返回值转自定义Price类型的ConverterNotFoundException问题
问题原因
你的PriceConverter是JPA的AttributeConverter,它仅负责实体属性与数据库列之间的双向转换。但当使用SUM(x.price)这类聚合函数时,查询返回的是原生BigDecimal值(被Spring Data JPA包装为TupleBackedMap),此时JPA属性转换器不会触发,Spring Data找不到对应类型的转换逻辑,因此抛出该异常。
解决方法
方法1:修改Repository返回类型,手动转换
将Repository方法的返回值改为BigDecimal,在业务代码中手动转换为Price对象:
@Query("SELECT SUM(x.price) FROM YourEntity x WHERE ...") BigDecimal sumPrice();
业务层调用示例:
BigDecimal sum = yourRepository.sumPrice(); Price totalPrice = sum != null ? new Price(sum) : null;
此方法简单直接,适合场景单一的情况。
方法2:注册Spring全局类型转换器
添加Spring原生Converter,让框架自动处理BigDecimal到Price的转换:
import org.springframework.core.convert.converter.Converter; import org.springframework.stereotype.Component; @Component public class BigDecimalToPriceConverter implements Converter<BigDecimal, Price> { @Override public Price convert(BigDecimal source) { return source != null ? new Price(source) : null; } }
若仍存在TupleBackedMap转换问题,可补充对应转换器:
import org.springframework.data.jpa.repository.query.AbstractJpaQuery; import org.springframework.core.convert.converter.Converter; import org.springframework.stereotype.Component; import java.math.BigDecimal; import java.util.Map; @Component public class TupleBackedMapToPriceConverter implements Converter<AbstractJpaQuery.TupleConverter.TupleBackedMap, Price> { @Override public Price convert(AbstractJpaQuery.TupleConverter.TupleBackedMap source) { if (source == null || source.isEmpty()) { return null; } BigDecimal value = (BigDecimal) source.values().iterator().next(); return new Price(value); } }
注册后Spring会自动识别并应用这些转换器。
方法3:使用构造函数投影
定义投影类,通过构造函数接收BigDecimal并转换为Price:
public class PriceProjection { private final Price totalPrice; public PriceProjection(BigDecimal totalPrice) { this.totalPrice = new Price(totalPrice); } public Price getTotalPrice() { return totalPrice; } }
修改Repository查询语句,指定返回该投影:
@Query("SELECT new com.yourpackage.PriceProjection(SUM(x.price)) FROM YourEntity x WHERE ...") PriceProjection sumPrice();
调用时直接从投影对象中获取Price实例即可。
方法4:自定义Repository实现
若以上方法不适用,可自定义Repository实现类,手动处理查询结果转换:
// 自定义Repository接口 public interface CustomYourRepository { Price sumPrice(); } // 实现类 @Repository public class CustomYourRepositoryImpl implements CustomYourRepository { @PersistenceContext private EntityManager entityManager; @Override public Price sumPrice() { BigDecimal sum = (BigDecimal) entityManager.createQuery("SELECT SUM(x.price) FROM YourEntity x WHERE ...") .getSingleResult(); return sum != null ? new Price(sum) : null; } } // 主Repository接口继承自定义接口 public interface YourRepository extends JpaRepository<YourEntity, Long>, CustomYourRepository { }
内容的提问来源于stack exchange,提问作者Thomas
相关产品推荐
相关产品推荐

