You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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); // 从列表移除 → 应从数据库删除
    }
}

错误原因

  1. 查找逻辑完全失效:代码刚把actGPs重置为空列表,后续从空列表里查找actGP必然返回null,导致所有旧实体都会留在oldActGPs中被标记为待删除,包括本应保留的实体。
  2. 实体删除方式错误:仅通过setInvoiceDetail(null)断开关联,没有正确通知JPA删除实体,导致持久化上下文状态混乱,合并时触发异常。
  3. 列表变更未被跟踪:直接给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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 00:54:54