双向一对一映射中如何删除子实体而不删除父实体?
问题解决方案
问题根源分析
@Immutable注解导致删除失效:Child实体标注了@Immutable,Hibernate会将其视为不可变对象,直接跳过DELETE语句执行,这是删除无报错但记录未消失的核心原因。- 双向映射配置错误:Parent类中
@OneToOne的mappedBy属性写为"intelligentGroup",但Child类中对应的关联字段是parent,映射名称不匹配,导致Hibernate无法正确识别双向关联关系。 - 非空约束冲突:直接将Parent的
child设为null时,Hibernate会尝试更新Child的parent_id为null,触发数据库的非空约束异常。
解决步骤
移除Child实体的
@Immutable注解
该注解会阻止Hibernate对Child执行修改或删除操作,必须移除才能正常执行删除逻辑:@Entity @Table(name = "child") // 移除@Immutable注解 public class Child { @OneToOne @JoinColumn(name = "parent_id", referencedColumnName = "id") private Parent parent; // 其他字段、getter/setter }修正双向映射的
mappedBy属性
Parent类中@OneToOne的mappedBy应指向Child类中的关联字段parent,确保双向关联关系正确建立:@Entity @Table(name = "parent") @TypeDefs({@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)}) public class Parent { // 修正mappedBy值为"parent" @OneToOne(cascade = CascadeType.ALL, mappedBy = "parent") private Child child; // 其他字段、getter/setter }正确执行删除逻辑
由于Child的parent_id是非空约束,删除Child时无需修改Parent的关联(Parent是关联的被拥有方,关联关系由Child维护),直接删除Child即可,注意操作需在事务中执行:@Transactional public void deleteChild(Long childId) { Child child = childRepo.findById(childId) .orElseThrow(() -> new RuntimeException("Child not found")); childRepo.delete(child); }
补充说明
如果需要在删除Child后清理Parent内存中的无效关联,可在删除前解除内存中的关联关系,此操作不会触发数据库更新,因此不会违反非空约束:
@Transactional public void deleteChild(Long childId) { Child child = childRepo.findById(childId) .orElseThrow(() -> new RuntimeException("Child not found")); Parent parent = child.getParent(); // 仅清理内存中的关联,不触发数据库操作 parent.setChild(null); childRepo.delete(child); }
内容的提问来源于stack exchange,提问作者Ashmita Kanojia
相关产品推荐
相关产品推荐

