Spring Data查询出现ORA-01722: invalid number错误求助
解决Spring Data中ORA-01722错误并通过@EmbeddedId获取Department主键
首先,咱们先拆解下问题:ORA-01722本质是字符串与数字类型不匹配导致的隐式转换失败——你的原生SQL是手动关联了两张表的非主键字段(类型匹配),但Spring Data自动生成的查询可能错误地把某个字符串字段和Department的数字类型主键deptno做了关联,触发了转换错误。用@EmbeddedId的思路是对的,尤其是当你的关联关系基于非主键字段,且需要明确映射复合关联条件时,下面是分步实现方案:
1. 定义@Embeddable的复合关联键类
首先创建一个实现Serializable的嵌入式类,用来封装两张表之间的非主键关联字段(这是避免类型不匹配的核心)。假设你的关联字段是Employee表的deptCode(字符串类型)和Department表的deptCode(同类型),代码如下:
import jakarta.persistence.Embeddable; import java.io.Serializable; import java.util.Objects; @Embeddable public class DeptAssociationId implements Serializable { private String deptCode; // 这里是你的非主键关联字段,类型要和两张表的对应字段完全一致 // 必须要有无参构造器(JPA要求) public DeptAssociationId() {} public DeptAssociationId(String deptCode) { this.deptCode = deptCode; } // 重写equals和hashCode(复合键必须实现) @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; DeptAssociationId that = (DeptAssociationId) o; return Objects.equals(deptCode, that.deptCode); } @Override public int hashCode() { return Objects.hash(deptCode); } // getter和setter public String getDeptCode() { return deptCode; } public void setDeptCode(String deptCode) { this.deptCode = deptCode; } }
2. 修改实体类的映射关系
(1)调整Department实体
确保Department的非主键关联字段(比如deptCode)被正确映射,同时保留主键deptno:
import jakarta.persistence.*; @Entity @Table(name = "DEPARTMENT") public class Department { @Id @Column(name = "DEPTNO") private Integer deptno; // 你的数字类型主键 @Column(name = "DEPT_CODE") private String deptCode; // 非主键关联字段 // 其他字段、构造器、getter/setter省略 }
(2)调整关联实体(比如Employee)
用@EmbeddedId标记复合键,再通过@MapsId和@ManyToOne关联到Department,确保关联基于非主键字段:
import jakarta.persistence.*; @Entity @Table(name = "EMPLOYEE") public class Employee { @EmbeddedId private DeptAssociationId id; // 嵌入式复合键 // 通过复合键中的deptCode关联到Department的deptCode @ManyToOne @JoinColumn(name = "DEPT_CODE", referencedColumnName = "DEPT_CODE", insertable = false, updatable = false) @MapsId("deptCode") // 关联复合键中的deptCode字段 private Department department; // 其他业务字段、构造器、getter/setter省略 // 示例:获取Department的主键deptno public Integer getDepartmentDeptno() { return department != null ? department.getDeptno() : null; } }
3. 编写Spring Data Repository查询
现在你可以正常编写Repository方法,Spring Data会基于嵌入式键的正确关联字段生成SQL,避免类型不匹配:
import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; public interface EmployeeRepository extends JpaRepository<Employee, DeptAssociationId> { // 示例:查询所有关联了Department的Employee,同时能获取Department的deptno List<Employee> findAllByDepartmentIsNotNull(); }
关键注意事项
- 字段类型严格匹配:确保嵌入式键中的关联字段类型和数据库表字段完全一致(比如都是VARCHAR2,不要一边是String一边是Integer),这是解决ORA-01722的核心。
- @MapsId的作用:它会将实体中的关联字段与嵌入式键中的字段绑定,避免重复映射。
- Serializable必须实现:嵌入式键类必须实现Serializable,否则JPA会抛出序列化异常。
如果你的关联场景更复杂(比如多个非主键字段关联),只需要在DeptAssociationId中添加对应字段,并在@MapsId中指定多个字段即可。
内容的提问来源于stack exchange,提问作者Angular_Newbie
相关产品推荐
相关产品推荐

