Spring Data JPA使用Interface Projection查询返回值全为null如何解决
问题原因
你遇到的返回全空核心原因是手动编写JPQL查询单个字段时,返回结果的别名和投影接口的属性名无法匹配:
从你打印的执行SQL可以看到,查询的两个字段自动生成的别名是col_0_0_、col_1_0_,和投影接口EntryTitleDateAndUserIdDTO的title、creationDate属性名完全不对应,Spring Data无法完成属性映射,因此所有字段都为null。
解决方案
这里提供两种可行的修复方式:
方案1:调整JPQL适配接口投影(推荐)
接口投影不需要你手动指定查询字段,Spring Data会自动根据接口定义的getter方法生成只查询对应字段的SQL,你只需要修改Repository的查询方法即可:
// 直接查询实体,返回类型声明为投影接口,Spring Data会自动处理投影逻辑 @Query("SELECT e FROM Entry e WHERE e.user = ?1") List<EntryTitleDateAndUserIdDTO> getAllEntriesOfUser(User user);
如果你坚持要手动指定查询字段,需要给字段设置和投影属性名一致的别名:
@Query("SELECT e.title as title, e.creationDate as creationDate FROM Entry e WHERE e.user = ?1") List<EntryTitleDateAndUserIdDTO> getAllEntriesOfUser(User user);
方案2:使用类投影(DTO)
如果你更倾向用实体类接收结果,可以定义一个包含对应字段和构造方法的DTO类:
// 注意替换成你自己的实际包路径 package com.yourpackage.dto; import java.time.Instant; public class EntryTitleDateDTO { private String title; private Instant creationDate; // 必须要有和查询字段顺序、类型完全匹配的构造方法 public EntryTitleDateDTO(String title, Instant creationDate) { this.title = title; this.creationDate = creationDate; } // Getter和Setter public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public Instant getCreationDate() { return creationDate; } public void setCreationDate(Instant creationDate) { this.creationDate = creationDate; } }
然后修改Repository的查询方法,使用JPQL的NEW关键字指定DTO全类名:
@Query("SELECT NEW com.yourpackage.dto.EntryTitleDateDTO(e.title, e.creationDate) FROM Entry e WHERE e.user = ?1") List<EntryTitleDateDTO> getAllEntriesOfUser(User user);
其他注意事项
- Repository方法的返回类型建议使用
List接口而非具体的ArrayList实现类,Spring Data会自动返回对应实现 - 你现有代码中的
deleteEntry方法需要添加@Modifying注解,且DELETE查询的返回类型应为int(影响行数)或void,不能返回Entry类型,否则会执行报错
内容的提问来源于stack exchange,提问作者Timon
相关产品推荐
相关产品推荐

