Spring Boot JPA联表查询返回DTO部分字段为Null求助
问题原因及解决方案
你的问题核心是原生SQL查询结果与接口DTO的映射不匹配,导致Jackson序列化时部分字段返回null。虽然Spring Data JPA支持接口投影,但在原生查询场景下,接口方法与SQL列名的自动映射(驼峰转下划线)偶尔会出现失效,尤其是涉及关联查询和复杂类型时。
解决方案:改用类投影(Class Projection)
将原有的接口形式DTO改为带构造方法和Getter的静态内部类,Spring Data JPA会自动完成列名到属性的映射,Jackson序列化也更稳定。
1. 修改SchedulerAdminResponse类
@Getter @AllArgsConstructor @NoArgsConstructor public class SchedulerAdminResponse { private List<ScheduleDTO> scheduleDto; private CountProcessDTO countProcessDto; // 改为静态内部类,添加全参构造器和Getter @Getter @AllArgsConstructor public static class ScheduleDTO { private Long adminScheduleId; private String title; private String description; private Long userScheduleId; private String fullName; private Progress progress; private LocalDateTime scheduleStart; } @Getter @AllArgsConstructor public static class CountProcessDTO { private Integer waiting; private Integer accepted; private Integer refused; } }
2. 调整Repository查询(无需修改SQL,保持原别名)
Spring Data JPA会自动将SQL中的下划线命名列(如admin_schedule_id)映射到类的驼峰命名属性(adminScheduleId),原Repository代码无需改动。
3. 可选:优化统计查询避免null值
如果某些状态没有数据,统计查询会返回null,可通过COALESCE函数将null转为0:
@Query(value = "SELECT COALESCE(SUM(T.WAITING), 0) AS waiting, COALESCE(SUM(T.ACCEPTED), 0) AS accepted, COALESCE(SUM(T.REFUSED), 0) AS refused " + "FROM (" + " SELECT " + " CASE WHEN progress = 'WAITING' THEN COUNT(progress) END AS WAITING, " + " CASE WHEN progress = 'ACCEPT' THEN COUNT(progress) END AS ACCEPTED, " + " CASE WHEN progress = 'REFUSE' THEN COUNT(progress) END AS REFUSED " + " FROM scheduler_user_tb WHERE scheduler_admin_id = :id GROUP BY progress) AS T", nativeQuery = true) SchedulerAdminResponse.CountProcessDTO countScheduleGroupByProgressById(Long id);
为什么接口投影会失效?
接口投影依赖Spring Data JPA动态生成代理类实现接口方法,在原生查询中,若列名与方法名的驼峰转换存在歧义(如关联表字段、枚举/日期类型),代理类可能无法正确绑定查询结果,导致序列化时返回null。类投影通过显式的属性和构造方法,避免了这种动态代理的不确定性。
内容的提问来源于stack exchange,提问作者user14012812
相关产品推荐
相关产品推荐

