Spring Boot中OneToMany关联场景下父子实体保存更新问题求助
问题根因说明
- 第一种方案保存后office为空:双向OneToMany关联中,
mappedBy = "compania"指定了关联关系的维护方是Office实体的compania字段,你只把Office加入了Compania的集合,没有给Office设置compania属性,导致数据库中office表的compania_id字段为空,查询时自然关联不到数据。另外你原有代码中变量名拼写错误,把查询到的companiaFound写成了未定义的companiaEnc,也是保存失败的直接原因。 - 第二种方案递归报错:JSON序列化时,Compania序列化其office集合,每个Office对象又会序列化其compania属性,形成无限循环导致栈溢出。
修复步骤
1. 修正实体类配置
处理JSON序列化递归问题
在关联字段上添加Jackson注解打断循环,二选一即可:
- 方案A:在Office的
compania字段上加@JsonIgnore,序列化Office时直接忽略关联的Compania对象 - 方案B:分别在父子实体的关联字段上加配对注解,适合需要在部分场景返回关联信息的情况:
// Compania类的office字段加 @JsonManagedReference @OneToMany( mappedBy = "compania", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true ) private List<Office> office = new ArrayList<>(); // 记得初始化集合避免空指针 // Office类的compania字段加 @JsonBackReference @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "compania_id", referencedColumnName = "id") private Compania compania;
封装关联维护方法
在Compania类中添加关联操作的工具方法,避免每次手动维护两侧关联时漏写:
// 添加Office public void addOffice(Office office) { office.setCompania(this); this.office.add(office); } // 移除Office public void removeOffice(Office office) { office.setCompania(null); this.office.remove(office); }
功能实现示例
POST新增Office
@Transactional public Office addOffice(Long companiaId, Office officeReq) { // 查询父实体,不存在抛出业务异常 Compania compania = companiaRepository.findById(companiaId) .orElseThrow(() -> new RuntimeException("公司不存在,id:" + companiaId)); // 重置id,避免前端传id导致意外更新已有数据 officeReq.setId(null); // 用封装方法添加关联,自动维护两侧关系 compania.addOffice(officeReq); // 保存父实体,cascade=ALL配置会自动级联保存新的Office Compania savedCompania = companiaRepository.save(compania); // 返回新增的Office对象 return savedCompania.getOffice().get(savedCompania.getOffice().size() - 1); }
PUT编辑已有Office
@Transactional public Office updateOffice(Long companiaId, Long officeId, Office officeReq) { // 查询父实体 Compania compania = companiaRepository.findById(companiaId) .orElseThrow(() -> new RuntimeException("公司不存在,id:" + companiaId)); // 查询要编辑的Office,校验是否属于当前公司 Office existOffice = officeRepository.findById(officeId) .filter(o -> o.getCompania().getId().equals(companiaId)) .orElseThrow(() -> new RuntimeException("办公点不存在或不属于当前公司,id:" + officeId)); // 更新可编辑字段 existOffice.setTitle(officeReq.getTitle()); existOffice.setName(officeReq.getName()); existOffice.setPath(officeReq.getPath()); existOffice.setIdRef(officeReq.getIdRef()); // 保存更新 return officeRepository.save(existOffice); }
注意事项
- 所有涉及数据库读写的方法必须加
@Transactional注解,避免懒加载失败、事务未提交等问题 - 不要直接调用
Optional.get(),必须处理查询结果为空的场景 - Office类的id字段上加了
@JsonIgnore,如果需要将id返回给前端可以移除该注解
内容的提问来源于stack exchange,提问作者Varox
相关产品推荐
相关产品推荐

