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

Hibernate报错:带有cascade='all-delete-orphan'的集合不再被所属实体实例引用的问题求助

Hibernate报错:带有cascade='all-delete-orphan'的集合不再被所属实体实例引用的问题求助

各位好,我现在遇到一个头疼的Hibernate问题,实在搞不定了,来请教大家!

我有个ProcedureStep实体,其中的subSteps集合配置了CascadeType.ALL和orphanRemoval = true。现在当我尝试保存从前端传来的实体时,总是抛出这个错误:

A collection with cascade='all-delete-orphan' was no longer referenced by the owning entity instance: br.com.unika.pathdetail.entity.ProcedureStep.subSteps.

奇怪的是,我在Java代码里并没有修改或者重新赋值这个subSteps集合啊——我只是把前端传过来的内容直接转成实体就保存了。但Hibernate好像还是认为原来的集合引用被替换或者丢失了。

我已经试过各种能想到的办法了,比如检查集合的初始化逻辑、确认没有在代码里重新new ArrayList()赋值,但都没用。下面是我的相关代码:

1. ProcedureStep实体类

@Entity
@Table(name = "procedure_step", indexes = {
        @Index(name = "idx_pstep_code", columnList = "code, procedure_id"),
})
@Data
public class ProcedureStep extends AbstractEntity<ProcedureStep, ProcedureStepDTO> {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @AuditableObject(mapBy = "id")
    @ManyToOne(fetch = FetchType.EAGER, optional = false)
    @JoinColumn(name = "account_id", updatable = false)
    private Account account;

    @AuditableObject(mapBy = "name")
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "procedure_id", updatable = false)
    private Procedure procedure;

    @AuditableObject(mapBy = "name")
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "parent_step_id")
    private ProcedureStep parentStep;

    // ex: 1.1.1
    @Auditable
    @Column(nullable = false, length = 20)
    private String code;

    @Auditable
    @Column(name = "name", nullable = false)
    private String name;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(nullable = false, name = "created_date", updatable=false)
    private Date createdDate = new Date();

    @OneToMany(mappedBy = "step", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<StepParameter> parameters = new ArrayList<>();

    @OneToMany(mappedBy = "parentStep", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<ProcedureStep> subSteps = new ArrayList<>();
}

2. 批量保存方法saveMany

@Transactional(rollbackFor = Exception.class)
public List<ProcedureStepDTO> saveMany(List<ProcedureStepDTO> dtoList) throws BusinessRuleException {
    Set<String> newObjs = new HashSet<>();

    // 把所有DTO转成实体
    List<ProcedureStep> toSave = dtoList.stream().map(ProcedureStepDTO::toEntity).toList();

    for (ProcedureStep entity : toSave) {
        validateUpdatePermission(entity);
        if(entity.getId() == null) {
            newObjs.add(entity.getUuidCheck());
            beforePersist(entity);
        } else {
            beforeSave(entity);
        }
        commonValidations(entity);
    }

    List<ProcedureStep> saved = repository.saveAll(toSave);

    for (ProcedureStep s : saved) {
        if(newObjs.contains(s.getUuidCheck())) {
            this.afterPersist(s);
        } else {
            this.afterSave(s);
        }
    }

    return saved.stream().map(ProcedureStep::toDTO).toList();
}

3. DTO转实体的toEntity方法

@Override
public ProcedureStep toEntity() {
    ProcedureStep entity = new ProcedureStep();
    this.mapCommonFields(entity);

    entity.setCode(this.getCode());
    entity.setName(this.getName());
    entity.setCreatedDate(this.getCreatedDate());

    if (this.account != null) {
        entity.setAccount(this.account.toEntity());
    }
    if (this.procedure != null) {
        entity.setProcedure(this.procedure.toEntity());
    }

    // 更新parameters集合
    if (entity.getParameters() == null) {
        entity.setParameters(new ArrayList<>());
    }
    entity.getParameters().clear();
    if (this.getParameters() != null && !this.getParameters().isEmpty()) {
        this.getParameters().forEach(parameter -> entity.getParameters().add(parameter.toEntity()));
    }

    // 更新subSteps集合
    if (entity.getSubSteps() == null) {
        entity.setSubSteps(new ArrayList<>());
    }
    entity.getSubSteps().clear();
    if (this.getSubSteps() != null && !this.getSubSteps().isEmpty()) {
        this.getSubSteps().forEach(subStepDTO -> entity.getSubSteps().add(subStepDTO.toEntity()));
    }

    return entity;
}

我特意在toEntity里用了先清空集合、再逐个添加元素的方式,完全没有重新赋值集合引用(比如entity.setSubSteps(new ArrayList<>())这种操作只有在集合为null的时候才会做,但实体里已经初始化了集合啊)。

实在搞不懂为什么Hibernate还是会报这个错,有没有大佬遇到过类似的情况?求指点一下可能的原因和解决办法,万分感谢!

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 06:17:59