You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot 3.2.5原生查询转换失败,JPQL正常的原因咨询

Spring Boot 3.2.5:原生SQL查询报类型转换错误,JPQL却正常的原因

错误栈追踪

org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.Integer] to type [com.train.management.entities.TrainDetails]
    at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:294) ~[spring-core-6.1.6.jar:6.1.6]
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:185) ~[spring-core-6.1.6.jar:6.1.6]
    at org.springframework.core.convert.support.ArrayToObjectConverter.convert(ArrayToObjectConverter.java:68) ~[spring-core-6.1.6.jar:6.1.6]
    at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:41) ~[spring-core-6.1.6.jar:6.1.6]
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:182) ~[spring-core-6.1.6.jar:6.1.6]
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:165) ~[spring-core-6.1.6.jar:6.1.6]
    at org.springframework.data.repository.query.ResultProcessor$ProjectingConverter.convert(ResultProcessor.java:305) ~[spring-data-commons-3.2.5.jar:3.2.5]
    at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.lambda$and$0(ResultProcessor.java:233) ~[spring-data-commons-3.2.5.jar:3.2.5]
    at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:240) ~[spring-data-commons-3.2.5.jar:3.2.5]
    at org.springframework.data.repository.query.ResultProcessor.processResult(ResultProcessor.java:160) ~[spring-data-commons-3.2.5.jar:3.2.5]
    at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:152) ~[spring-data-jpa-3.2.5.jar:3.2.5]
    at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:137) ~[spring-data-jpa-3.2.5.jar:3.2.5]

相关代码

TrainDetails实体类

@Entity
@Table(name = "train_details")
public class TrainDetails {
    
    @Id
    @Column(name = "train_id")
    private String id;
    
    @Column(name = "train_name")
    private String trainName;
    
    @Column(name = "total_distance_covers")
    private String totalDistance;
    
    @Column(name = "train_code")
    private String trainCode;
    
    @Column(name = "total_stops")
    private int totalStops;
    
    @ManyToOne
    @JoinColumn(name = "start_station")
    private Station startStation;
    
    
    @ManyToOne
    @JoinColumn(name = "end_station")
    private Station endStation;

    @OneToMany(mappedBy = "trainName", cascade = CascadeType.ALL)
    private List<Coach> coaches;
}

StationRepo仓库接口

报错的原生SQL查询

public interface StationRepo extends JpaRepository<Station, String> {
    // 原生SQL查询(报错)
    @Query(nativeQuery = true, value="SELECT td.*\r\n"
            + "FROM train_details td\r\n"
            + "JOIN station s_start ON td.start_station = s_start.station_id\r\n"
            + "JOIN station s_end ON td.end_station = s_end.station_id\r\n"
            + "WHERE s_start.station_code = ?1"
            + " OR s_end.station_code = ?1")
    public List<TrainDetails> getAllTrainsComingOnStation(String stationCode);
}

正常工作的JPQL查询

public interface StationRepo extends JpaRepository<Station, String> {
    @Query("SELECT td FROM TrainDetails td\r\n"
            + "JOIN td.startStation s_start\r\n"
            + "JOIN td.endStation s_end\r\n"
            + "WHERE s_start.stationCode = :stationCode\r\n"
            + "   OR s_end.stationCode = :stationCode\r\n")
    public List<TrainDetails> getAllTrainsComingOnStation(@Param("stationCode") String stationCode);
}

原因解析

1. JPQL面向实体,自动处理关联映射

JPQL直接操作你定义的实体类和关联关系,JPA会自动解析td.startStation这类实体关联逻辑,查询结果会被完整映射为TrainDetails对象——即使关联的Station是懒加载,也会生成代理对象填充到对应属性中,不会出现类型不匹配问题。

2. 原生SQL仅返回数据库字段,无法自动处理实体关联

原生SQL是直接针对数据库表的查询,SELECT td.*只会返回train_details表的所有字段,其中start_station和end_station是存储外键值的字段(比如数字或字符串类型)。但你的TrainDetails类中这两个属性是Station类型的实体,Spring Data JPA不会自动把外键值转换为对应的Station实体,而是试图直接将外键值赋值给Station类型的属性,最终触发类型转换异常(栈追踪中显示的Integer转TrainDetails是转换链中的最终异常,本质是外键值无法转成Station实体)。

3. 原生SQL的可选解决方案

  • 使用@SqlResultSetMapping手动定义结果映射,将外键字段关联到Station实体;
  • 改用DTO类接收查询结果,避免返回包含关联实体的TrainDetails;
  • 在原生SQL中查询关联表的字段,手动组装实体(不推荐,冗余且易出错)。

内容的提问来源于stack exchange,提问作者Rani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 12:22:34