JPA2+Hibernate5环境修改父类关联集合后孤儿实体未被删除问题
问题根因
你遇到的orphanRemoval不生效、子实体未被删除的问题,核心是两个常见的JPA使用误区:
- 实体
equals/hashCode实现不符合持久化场景要求,导致集合remove操作实际未成功移除元素,无法触发孤儿删除机制 - 测试未开启事务,实体在两次save之间变为脱管态,merge操作无法正确识别集合变更触发删除
解决方案
1. 修复equals与hashCode实现
父类ChildBase新增基于主键的相等判断逻辑,避免默认内存地址比较导致的集合操作失效:
@Entity @Table(name = "childs") @Getter @Setter @ToString @Accessors(chain = true) @NoArgsConstructor @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @EqualsAndHashCode(onlyExplicitlyIncluded = true) // 新增 public abstract class ChildBase { @Id @GeneratedValue(strategy = GenerationType.AUTO) @EqualsAndHashCode.Include // 仅用主键作为相等判断依据 protected long id; @JoinColumn(nullable = false) @ManyToOne @ToString.Exclude protected Parent parent; public ChildBase(Parent parent){ this.parent = parent; } }
小提示:建议将Parent和ChildBase的主键类型从基本类型long改为包装类型Long,避免未持久化实体主键默认值0带来的相等判断异常
2. 测试方法添加事务支持
保证整个测试逻辑在同一个持久化上下文中执行,避免实体脱管,同时同步维护关联关系两端:
@Test @Transactional // 新增事务注解 @Rollback // 可选,测试结束自动回滚测试数据 public void test(){ Parent parent = new Parent(); MyChild child1 = new MyChild("a", parent); MyChild child2 = new MyChild("a", parent); parent.getChilds().add(child1); parentRepository.save(parent); parent.getChilds().remove(child1); child1.setParent(null); // 同步清空关系维护端的引用,符合JPA规范 parent.getChilds().add(child2); parentRepository.save(parent); }
调整后执行测试,即可符合预期仅保留第二个子实体的记录。
内容的提问来源于stack exchange,提问作者Dev93
相关产品推荐
相关产品推荐

