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

Hibernate使用addScalar映射NativeQuery到DTO时报列不存在错误

问题根因

报错java.sql.SQLException: Column 'absenceId' not found的核心原因是SQL返回的列名、addScalar声明的列名、DTO属性名三者不匹配,同时代码存在多处映射疏漏和不规范写法:

  • SQL查询的数据库字段以下划线命名,且没有配置对应别名:比如查询的a.absence_id返回列名是absence_id,但addScalar中声明的列名是驼峰格式的absenceId,数据库返回结果里根本不存在这个名称的列,直接触发列找不到的错误。同理create_date、date_off、enable_date等字段都存在这个问题。
  • 字段映射错配:DTO中定义的是startDate属性,但SQL查询的是create_date、addScalar声明的是createDate,三者完全不对应;SQL查询了date_off字段,但DTO里根本没有定义dateOff属性,后续就算列名匹配也会映射失败。
  • 存在SQL注入风险:直接拼接用户传入的id参数到SQL字符串,没有使用参数占位符。
  • DTO类缺失必要结构:没有无参构造、没有属性对应的getter/setter方法,fullNameOfDepartment字段末尾缺失分号,aliasToBean转换器无法通过反射完成属性赋值。
修正方案

1. 调整查询语句,统一列别名,改用参数传值

SQL中所有查询字段必须起和addScalar、DTO属性名完全一致的别名,参数改用命名占位符传递,避免SQL注入:

public List<AbsenceResponse> findAllByUserId1(Long id) {
    StringBuilder sql = new StringBuilder();
    sql.append(
            "SELECT  a.absence_id as absenceId, " +
            "a.create_date as startDate, " +
            "a.end_date as endDate," +
            "a.date_off as dateOff," +
            "a.title as title," +
            "a.description as description," +
            "a.status as status," +
            "a.type as type," +
            "a.enable_date as enableDate, " +
            "u.full_name as fullNameOfDepartment");
    sql.append(" FROM absence a ");
    sql.append(" INNER JOIN user u ON u.user_id = a.absence_by ");
    sql.append(" WHERE a.user_id = :userId");

    List<AbsenceResponse> res = entityManager.unwrap(org.hibernate.Session.class)
            .createNativeQuery(sql.toString())
            .addScalar("absenceId", LongType.INSTANCE)
            .addScalar("startDate", DateType.INSTANCE)
            .addScalar("endDate", DateType.INSTANCE)
            .addScalar("dateOff", IntegerType.INSTANCE)
            .addScalar("title", StringType.INSTANCE)
            .addScalar("description", StringType.INSTANCE)
            .addScalar("status", IntegerType.INSTANCE)
            .addScalar("type", IntegerType.INSTANCE)
            .addScalar("enableDate", DateType.INSTANCE)
            .addScalar("fullNameOfDepartment", StringType.INSTANCE)
            .setParameter("userId", id)
            .setResultTransformer(Transformers.aliasToBean(AbsenceResponse.class))
            .list();
    return res;
}

2. 补全DTO类结构

新增缺失的dateOff属性,补全无参构造和所有属性的getter/setter方法,修正语法笔误:

import java.util.Date;

public class AbsenceResponse {
    private Long absenceId;
    private Date startDate;
    private Date endDate;
    private Integer dateOff;
    private String title;
    private String description;
    private int status;
    private int type;
    private Date enableDate;
    private String fullNameOfDepartment;

    // 别名转换器必须依赖无参构造实例化对象
    public AbsenceResponse() {}

    // 补全所有属性的getter、setter
    public Long getAbsenceId() {return absenceId;}
    public void setAbsenceId(Long absenceId) {this.absenceId = absenceId;}
    public Date getStartDate() {return startDate;}
    public void setStartDate(Date startDate) {this.startDate = startDate;}
    public Date getEndDate() {return endDate;}
    public void setEndDate(Date endDate) {this.endDate = endDate;}
    public Integer getDateOff() {return dateOff;}
    public void setDateOff(Integer dateOff) {this.dateOff = dateOff;}
    public String getTitle() {return title;}
    public void setTitle(String title) {this.title = title;}
    public String getDescription() {return description;}
    public void setDescription(String description) {this.description = description;}
    public int getStatus() {return status;}
    public void setStatus(int status) {this.status = status;}
    public int getType() {return type;}
    public void setType(int type) {this.type = type;}
    public Date getEnableDate() {return enableDate;}
    public void setEnableDate(Date enableDate) {this.enableDate = enableDate;}
    public String getFullNameOfDepartment() {return fullNameOfDepartment;}
    public void setFullNameOfDepartment(String fullNameOfDepartment) {this.fullNameOfDepartment = fullNameOfDepartment;}
}
注意事项
  • addScalar传入的列名大小写敏感,必须和SQL中定义的字段别名完全一致,NativeQuery不会自动把数据库下划线命名转成驼峰命名。
  • Transformers.aliasToBean的映射规则是通过反射调用DTO属性对应的setter方法赋值,所以DTO必须有无参构造,所有待映射字段必须有public修饰的setter方法。
  • 如果使用Hibernate 5.2+版本,setResultTransformer已经被标记为废弃,可以改用TupleTransformer或者JPA自带的SqlResultSetMapping实现DTO映射,逻辑是一致的。

内容的提问来源于stack exchange,提问作者Phạm Cường

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 23:24:14