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

Java JPA自定义查询返回NULL问题排查求助

问题分析与修复方案

错误原因

  1. DTO错误标记为实体:WineDTO添加了@Entity注解,JPA会将其当作数据库实体处理,但查询结果并未返回DTO中定义的id字段,实体映射逻辑会干扰DTO的结果绑定流程。
  2. 字段类型不匹配:SQL的AVG()函数返回数值类型(如Double/BigDecimal),但DTO中用String类型接收,无法自动转换导致赋值为null。
  3. 缺少结果映射机制:原生查询结果映射到DTO需要明确的构造方法或字段绑定规则,否则JPA无法将查询列与DTO字段关联。
  4. 字段名大小写不兼容:H2数据库默认会将列名转为小写(例如查询别名avgTasteRating会变成avgtasterating),而DTO使用驼峰字段名,默认映射规则无法匹配。

修复步骤

1. 修正WineDTO定义

  • 移除@Entity注解(DTO是数据传输对象,不属于数据库实体)
  • 删除无用的id字段(查询未返回该列)
  • 将avg相关字段类型改为Double(匹配AVG()返回值类型)
  • 添加与查询列顺序一致的全参构造方法,并提供Getter方法(JPA需要通过Getter访问字段)

修复后的WineDTO.java:

public class WineDTO {

    private String name;
    private Double avgTasteRating;
    private Double avgDesignRating;
    private Double avgPriceRating;

    // 构造方法参数顺序必须与查询返回列顺序完全一致
    public WineDTO(String name, Double avgTasteRating, Double avgDesignRating, Double avgPriceRating) {
        this.name = name;
        this.avgTasteRating = avgTasteRating;
        this.avgDesignRating = avgDesignRating;
        this.avgPriceRating = avgPriceRating;
    }

    // 必须提供Getter方法
    public String getName() {
        return name;
    }

    public Double getAvgTasteRating() {
        return avgTasteRating;
    }

    public Double getAvgDesignRating() {
        return avgDesignRating;
    }

    public Double getAvgPriceRating() {
        return avgPriceRating;
    }
}

2. (可选)调整查询别名适配大小写

如果H2列名大小写问题仍然存在,可以将查询中的别名改为小写,并在DTO字段上添加@Column注解指定列名:

修改后的WineRepository.java查询:

@Query(value =
    "SELECT w.NAME, AVG(r.taste_rating) AS avgtasterating, AVG(r.design_rating) AS avgdesignrating,AVG(r.price_rating) AS avgpricerating" +
            "            FROM WINE w JOIN RATING r ON w.ID = r.wine_id" +
            "            GROUP BY w.ID, w.NAME" +
            "            ORDER BY avgtasterating DESC", nativeQuery = true)
List<WineDTO> findWinesWithAverageRatings();

对应的DTO字段添加注解:

import javax.persistence.Column;

public class WineDTO {

    private String name;
    
    @Column(name = "avgtasterating")
    private Double avgTasteRating;
    
    @Column(name = "avgdesignrating")
    private Double avgDesignRating;
    
    @Column(name = "avgpricerating")
    private Double avgPriceRating;

    // 构造方法和Getter同上
}

3. 验证映射逻辑

JPA会根据查询返回列的顺序,匹配DTO构造方法的参数顺序进行赋值,这是原生查询映射DTO最可靠的方式之一,修复后即可正常获取所有字段值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 00:40:06