Spring Boot接口接收嵌套JSON时如何持久化Cod实体到数据库
SpringBoot JPA多层级实体持久化问题
问题现状
- 接口接收
JSON格式请求,请求体结构如下:
{ "type": "1C", "counterparty": { "name": "ИП Петя", "inn": "123456789", "kpp": "" }, "nomenclatures": [ { "cod": [{"type":"1C", "val":"РТ-1234"}, {"type":"Front", "val":"567"}], "name": "Картоха", "article": "123" }, { "cod": [{"type":"1C", "val":"РТ-1234"}, {"type":"Front", "val":"567"}], "name": "Сникерс", "article": "459" } ] }
- 已按照业务模型创建对应数据库表,实体层级关联为:交易方
Counterparty关联单据主表NodeObject,单据主表关联多条商品Nomenclature,单条商品关联多条编码Cod。 - 需求为将请求JSON映射的全量实体数据全部持久化到数据库。
- 目前已完成
Counterparty、NodeObject、Nomenclature三个实体的保存逻辑,仅剩Cod实体无法正确落库,现有Controller层代码如下:
@PostMapping(value = "/item") public void postMain (@RequestBody NodeObject node) { Counterparty counterparty = new Counterparty(); counterparty.setName(node.getCounterparty().getName()); counterparty.setInn(node.getCounterparty().getInn()); counterparty.setKpp(node.getCounterparty().getKpp()); counterpartyRepository.save(counterparty); NodeObject nodeObject = new NodeObject(); nodeObject.setType(node.getType()); nodeObject.setId(counterparty.getId()); nodeObject.setCounterparty(counterparty); nodeObject.setNomenclatures(node.getNomenclatures()); nodeObjectRepository.save(nodeObject); Set<Nomenclature> nomenclatures = node.getNomenclatures(); nomenclatures.forEach(nomenclature -> nomenclature.setNodeObject(nodeObject)); nomenclatureRepository.saveAll(nomenclatures); // ???????????????????????? List<Cod> cod = new ArrayList<>(); }
- 请求JSON通过
@RequestBody直接绑定为NodeObject类型参数,需要补充Cod实体的关联设置与保存逻辑,实现全量数据正确落库。
解决方法
Cod落库失败的核心原因是Cod作为Nomenclature的关联子表,没有设置对应的外键关联,直接保存会因为关联字段为空触发约束报错。补全逻辑如下,替换代码中问号标注的部分即可:
List<Cod> allCodToSave = new ArrayList<>(); // 遍历所有已持久化、带主键ID的商品实体 for (Nomenclature nomenclature : nomenclatures) { List<Cod> cods = nomenclature.getCod(); if (cods == null || cods.isEmpty()) { continue; } // 为每个编码实体绑定所属商品,填充外键字段 for (Cod cod : cods) { cod.setNomenclature(nomenclature); allCodToSave.add(cod); } } // 批量保存所有编码数据 codRepository.saveAll(allCodToSave);
额外优化建议
现有代码的保存顺序存在小问题:nodeObjectRepository.save(nodeObject)执行时,关联的nomenclatures还未设置和NodeObject的绑定关系,也未持久化,容易产生临时字段脏数据。建议调整保存顺序为:
- 构造并保存
Counterparty - 构造
NodeObject,仅绑定type和Counterparty关联,先不要设置nomenclatures,保存NodeObject - 遍历请求中的
Nomenclature集合,给每个商品绑定所属NodeObject,批量保存所有Nomenclature - 再遍历已保存的
Nomenclature,处理Cod的关联绑定和批量保存
如果Nomenclature和Cod的JPA关联配置了cascade = CascadeType.ALL,甚至不需要手动写Cod的保存逻辑,保存Nomenclature时会自动级联保存关联的Cod,但前提是Cod已经正确添加@ManyToOne注解关联到Nomenclature。
内容的提问来源于stack exchange,提问作者tvisteljas
相关产品推荐
相关产品推荐

