InvoiceDetail处理ActGps时触发‘Cannot merge an entity that has been removed’报错
问题修复:"Cannot merge an entity that has been removed" 错误
这段代码运行时抛出Cannot merge an entity that has been removed异常,核心问题是存在误删非目标实体的逻辑缺陷,且InvoiceDetail关联了ActGps列表。以下是代码的中文注释版及问题分析、修复方案:
原代码(中文注释)
// 初始化所需字段 List<ActGP> oldActGPs = new ArrayList<>(); if (actGPs != null && !actGPs.isEmpty()) oldActGPs.addAll(actGPs); actGPs = new ArrayList<>(); // 获取actGP(若存在于就诊记录且未取消) // 若存在 → 重置字段(重置价格) // 若不存在 → 创建新的ActGP actGP = actGPs.stream().filter(agp -> agp.getVGPId() == vgp.getId()).findAny().orElse(null); if (actGP == null) { // 从科室添加新操作 或 在就诊记录中添加新GP的情况 actGP = createNewActGP(vgp, currAct); } else { // actGP已存在 // 或调用reCompute方法的情况 actGP.resetPriceFields(); if (!oldActGPs.isEmpty()) oldActGPs.remove(actGP); // 循环结束后,oldActGPs中将保留已取消GP对应的actGP actGP.setGptId(0); } if (!oldActGPs.isEmpty()) { for (ActGP a : oldActGPs) { a.setInvoiceDetail(null); // 从列表移除 → 应从数据库删除 } }
错误原因
- 查找逻辑完全失效:代码刚把
actGPs重置为空列表,后续从空列表里查找actGP必然返回null,导致所有旧实体都会留在oldActGPs中被标记为待删除,包括本应保留的实体。 - 实体删除方式错误:仅通过
setInvoiceDetail(null)断开关联,没有正确通知JPA删除实体,导致持久化上下文状态混乱,合并时触发异常。 - 列表变更未被跟踪:直接给
actGPs赋值新列表,JPA无法感知原有关联的变更,进一步加剧状态不一致。
修复方案
1. 修正实体查找逻辑
从保存旧数据的oldActGPs中查找目标实体,而非空列表:
// 修正:从旧列表中匹配对应actGP actGP = oldActGPs.stream().filter(agp -> agp.getVGPId() == vgp.getId()).findAny().orElse(null);
2. 正确处理实体删除
使用JPA的EntityManager执行删除操作,确保持久化上下文同步:
if (!oldActGPs.isEmpty()) { for (ActGP a : oldActGPs) { a.setInvoiceDetail(null); entityManager.remove(a); // 通知JPA删除实体 } }
3. 保留原有列表以跟踪变更
避免直接替换列表,改用clear()清空原有列表:
// 替换actGPs = new ArrayList<>();为: actGPs.clear();
内容的提问来源于stack exchange,提问作者Zeinab Abbas
相关产品推荐
相关产品推荐

