Spring Boot JPA一对一关联保存Agency报非空属性引用空值异常
问题原因
报错是因为以下两个错误叠加导致的:
- 保存顺序错误:你先执行Agency的保存操作时,对应的Address对象还未被持久化到数据库,处于瞬时态,且你并未将Address对象关联到Agency的
address属性中,Agency的address字段配置了nullable=false非空约束,触发数据完整性校验失败。 - 表单绑定逻辑错误:前端表单的地址字段并未绑定到
agency.address对应的属性上,后端接收到的Agency对象的address属性默认为空。
解决方案
方案1:调整保存逻辑与关联关系(无需修改注解)
步骤1:修改控制器saveAgency方法逻辑
调整保存顺序,先持久化Address,再将持久化后的Address关联到Agency后再保存Agency:
@PostMapping("/agencies/save") public String saveAgency(@ModelAttribute("agency") Agency agency,@ModelAttribute("address") Address address) { // 先保存地址,得到已持久化、带有主键的地址对象 Address persistedAddress = addressService.saveAddress(address); // 关联地址到Agency agency.setAddress(persistedAddress); // 保存Agency agencyService.saveAgency(agency); return "redirect:/agencies"; }
方案2:优化关联配置与表单绑定(简化代码)
步骤1:修改Agency实体的一对一关联配置,添加级联持久化
因为Agency是外键维护方(@JoinColumn定义在Agency类中),将级联操作配置在Agency侧,保存Agency时会自动持久化关联的Address:
@OneToOne(fetch = FetchType.EAGER, optional = false, cascade = CascadeType.PERSIST) @JoinColumn(name="addressid", referencedColumnName = "id", nullable = false) private Address address;
步骤2:修改前端表单的地址字段绑定规则
将地址字段的name属性改为address.xxx,让SpringMVC自动封装到Agency的address属性中:
<input type="text" name="address.street" placeholder="Street" class="form-control mb-4 col-4"> <input type="text" name="address.streetNumber" placeholder="Street Number" class="form-control mb-4 col-4"> <input type="text" name="address.postalCode" placeholder="Postal Code" class="form-control mb-4 col-4">
步骤3:简化控制器保存逻辑
无需单独接收Address参数,也无需单独调用Address的保存方法:
@PostMapping("/agencies/save") public String saveAgency(@ModelAttribute("agency") Agency agency) { agencyService.saveAgency(agency); return "redirect:/agencies"; }
可选优化
如果需要维护双向关联的一致性,可在关联时同时给Address设置Agency属性:
// 在agency.setAddress(persistedAddress);后添加 persistedAddress.setAgency(agency); addressService.saveAddress(persistedAddress);
内容的提问来源于stack exchange,提问作者BlueMan
相关产品推荐
相关产品推荐

