Spring Boot向含外键的Reimbursement发POST请求报错:emp_id不能为空
问题:新增报销记录时提示“Column 'emp_id' cannot be null”
我有employee和reimbursement两张表,二者为一对多关联关系。向reimbursement发送POST请求时,出现错误提示“Column 'emp_id' cannot be null”(emp_id为外键)。
实体类代码
Employee类
@Entity @Table(name = "employee") public class Employee { @Id @GeneratedValue (strategy = GenerationType.IDENTITY) @Column(name = "emp_id") private long empId; @Column(name = "name", nullable = false) private String name; @Column(name = "email", nullable = false, unique = true) private String email; @Column(name = "password", nullable = false) private String password; @Column(name = "manager", nullable = false) @Value("false") private boolean manager; @OneToMany(mappedBy = "employee", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true ) @JsonManagedReference private Set<Reimbursement> reimbursements = new HashSet<>(); public long getEmpId() { return empId; } public void setEmpId(long empId) { this.empId = empId; } // (...) 其他getter和setter方法 public Set<Reimbursement> getReimbursements() { return reimbursements; } public void setReimbursements(Set<Reimbursement> reimbursements) { this.reimbursements = reimbursements; } }
Reimbursement类
@AllArgsConstructor @NoArgsConstructor @Entity @Table( name = "reimbursements" ) public class Reimbursement { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "description", nullable = false) private String description; @Column(name = "amount", nullable = false) private double amount; @Column(name = "status", nullable = false) @Value("false") private boolean status; //费用是否已报销 @ManyToOne @JoinColumn(name = "emp_id", nullable = false, updatable = false) @JsonBackReference private Employee employee; public Long getId() { return id; } public void setId(Long id) { this.id = id; } //(...) 其他getter和setter方法 public Employee getEmployee() { return employee; } public void setEmployee(Employee employee) { this.employee = employee; } }
控制器代码
@PostMapping public ResponseEntity<Reimbursement> createReimbursement(@RequestBody Reimbursement reimbursement) { var data = reimbursementService.createReimbursement(reimbursement); return new ResponseEntity<>(data, HttpStatus.CREATED); }
服务层代码
@Override public Reimbursement createReimbursement(Reimbursement reimbursement) { return reimbursementRepository.save(reimbursement); }
发送的POST请求JSON(id为1的员工已存在)
{ "employee": { "emp_id": "1" }, "description": "example", "amount": "123", "status": "false" }
问题原因及解决办法
JSON字段名与实体类属性不匹配
Employee类中主键属性是empId(小驼峰格式),但请求JSON里写的是emp_id(下划线格式)。Spring默认的Jackson序列化规则会匹配小驼峰属性,导致该字段无法正确映射,最终Employee对象的empId为long类型默认值0,Hibernate无法识别这个无效ID,导致外键emp_id为空。解决:修改请求JSON的字段名,并修正数据类型(
amount是double不用加引号,status是boolean直接传布尔值):{ "employee": { "empId": 1 }, "description": "example", "amount": 123, "status": false }未使用持久化的Employee对象
即使字段名正确,传入的只是一个仅含empId的临时Employee对象,不是从数据库加载的持久化实例。Hibernate保存Reimbursement时,会认为这个Employee是新对象,无法正确关联到已存在的员工记录,导致外键赋值失败。解决:在服务层先从数据库查询对应员工的持久化对象,再绑定到报销记录:
@Override public Reimbursement createReimbursement(Reimbursement reimbursement) { // 查询数据库中已存在的员工 Employee existingEmployee = employeeRepository.findById(reimbursement.getEmployee().getEmpId()) .orElseThrow(() -> new RuntimeException("指定员工不存在")); // 将持久化员工对象设置到报销记录 reimbursement.setEmployee(existingEmployee); return reimbursementRepository.save(reimbursement); }@Value注解误用
实体类中manager和status字段使用的@Value("false")是Spring的配置注入注解,不能用来设置实体类默认值。正确做法是直接在字段声明时赋值:// Employee类中 @Column(name = "manager", nullable = false) private boolean manager = false; // Reimbursement类中 @Column(name = "status", nullable = false) private boolean status = false;
内容的提问来源于stack exchange,提问作者sharpes
相关产品推荐
相关产品推荐

