JPA删除父实体无法联动删除子实体问题咨询
我在父实体(IRIDE/AcqPlan)与子实体(HeaderType/Header)之间建立了@OneToOne关联,需求是删除父实体时自动删除子实体(子实体无父实体则无意义)。
父实体代码
@Entity(name = "AcqPlan") @Table(name = "ACQ_PLAN") @Inheritance(strategy = InheritanceType.JOINED) public class IRIDE implements MpsIdEntity<Long>{ private static final long serialVersionUID = 1L; protected HeaderType header; protected Long id; @OneToOne(mappedBy = "acqPlan", cascade = { CascadeType.ALL }) public HeaderType getHeader() { return header; } /** * Sets the value of the header property. * * @param value * allowed object is * {@link HeaderType } * */ public void setHeader(HeaderType value) { this.header = value; } ...
子实体代码
@Entity(name = "Header") @Table(name = "HEADER") public class HeaderType implements MpsIdEntity<Long>{ protected Long id; protected IRIDE acqPlan; @OneToOne(optional=false, orphanRemoval = true, cascade = { CascadeType.ALL }) @JoinColumn(name = "AcqPLan_FK",nullable = false) public IRIDE getAcqPlan() { return acqPlan; } public void setAcqPlan(IRIDE acqPlan) { this.acqPlan = acqPlan; }
问题
- 为何ORM不生成DDL的OnDelete动作?
- 核心问题:当我在数据库执行语句
delete from acq_plan where acq_plan.id =1;时,仅父实体(acq_plan)记录被删除,关联的header记录未被删除,原因是什么?
问题1解答
你当前的关联配置里,父实体的header字段用了mappedBy = "acqPlan",说明子实体是关联关系的拥有端(因为@JoinColumn定义在子实体这边)。JPA的cascade = CascadeType.ALL是ORM层面的级联规则,和数据库层面的ON DELETE约束是两回事——默认情况下,JPA不会自动生成数据库级的ON DELETE CASCADE,必须显式配置才能触发DDL生成。
另外你加的orphanRemoval = true也是ORM层面的逻辑,负责清理和父实体断开关联的子实体,但同样不会影响数据库外键约束的生成。如果要让ORM生成ON DELETE CASCADE,可以在子实体的@JoinColumn里补充外键定义,比如用Hibernate的@OnDelete(action = OnDeleteAction.CASCADE),或者通用的foreignKey = @ForeignKey(foreignKeyDefinition = "FOREIGN KEY (AcqPLan_FK) REFERENCES ACQ_PLAN(id) ON DELETE CASCADE")。
问题2解答
直接用SQL语句在数据库删除父记录,完全绕开了JPA的ORM逻辑。你配置的cascade = CascadeType.ALL和orphanRemoval = true只有在通过JPA的EntityManager执行删除操作(比如entityManager.remove(irideEntity))时,才会触发框架自动级联删除子实体的行为。
而数据库层面没有配置ON DELETE CASCADE的外键约束,所以数据库本身不会自动关联删除子表记录,这就是直接删父表后子表记录还存在的原因。
内容的提问来源于stack exchange,提问作者KronosOne

