Spring Data JPA原生内连接查询如何用接口投影映射为DTO并解决报错
问题原因
select new 全类名是JPQL专属语法,你给查询加了nativeQuery = true走原生SQL逻辑,数据库无法识别该语法,因此直接抛出语法错误。- 你的子查询返回的列是
zone_no、amount_sum,外层查询却调用z.zone、z.amount,子查询中不存在这两个字段别名,也会导致SQL执行失败。 - 你定义了
IZoneAmountDTO接口但没有实际使用,反而在方法返回值里声明了实体类ZoneWiseTotalAmountDto,接口投影没有生效入口。
正确实现方案
方案1:使用IZoneAmountDTO接口投影(最简方案)
接口投影对原生SQL兼容性好,只需要保证查询返回的列别名和接口的getter方法严格对应即可:
- 无需修改已定义的
IZoneAmountDTO,getZone()对应别名zone、getAmount()对应别名amount完全符合要求。 - 调整Repository层查询代码,去掉错误的new语法、匹配列别名,将返回值改为接口类型:
public interface IZoneAmountDTO{ Integer getZone(); Double getAmount(); } @Query(value = "select USERS_TAXPAYER.zone_no as zone, sum(PAYMENT_DATA.amount) as amount from PAYMENT_DATA inner join USERS_TAXPAYER on PAYMENT_DATA.tin_no = USERS_TAXPAYER.tin_no group by USERS_TAXPAYER.zone_no",nativeQuery = true) List<IZoneAmountDTO> countZoneWiseReturnAmount();
直接调用该方法即可拿到自动映射完成的结果,无需额外配置。
方案2:继续使用ZoneWiseTotalAmountDto类
如果你一定要用该类作为返回值,有两种可选实现:
- 去掉
nativeQuery = true,改用JPQL编写查询,此时可以正常使用select new语法:
// 注意USERS_TAXPAYER、PAYMENT_DATA要换成你的实际实体类名,字段也要换成实体类的属性名 @Query(value = "select new com.example.nbr.entity.ZoneWiseTotalAmountDto(u.zoneNo, sum(p.amount)) from PaymentData p inner join UserTaxpayer u on p.tinNo = u.tinNo group by u.zoneNo") List<ZoneWiseTotalAmountDto> countZoneWiseReturnAmount();
- 必须使用原生SQL的话,需要额外添加
@SqlResultSetMapping配置字段映射关系,实现复杂度较高,更推荐使用方案1。
内容的提问来源于stack exchange,提问作者Md.Habibur Rahman
相关产品推荐
相关产品推荐

