1

我正在寻求帮助,因为当我尝试删除具有 OneToMany 关系的实体时,在加载带有列表的页面时出现此错误:

MySQLIntegrityConstraintViolationException:无法删除或更新父行:外键约束失败

当然,我知道这与级联删除儿童有关,但我不知道我在哪里做的不好。

父实体部分相对于与子关系的关系:

@Entity
@Table(name="PARENT")
public class Parent implements Serializable {
...
@OneToMany (mappedBy = "parent", orphanRemoval = true, cascade={CascadeType.ALL}, targetEntity = Children.class)
@JoinColumn(name = "parent_id")
private List <Children> children;
...
}

子实体部分相对于与父的关系:

@Entity
@Table(name = "CHILDREN")
public class Children implements Serializable {
...
@ManyToOne(targetEntity = Parent.class, cascade = CascadeType.ALL)
@JoinColumn
private Country country;

用于删除实体的 JSF 按钮:

<p:button onmouseup="#{parentBean.remove(parent)}" value="Delete" />

豆:

getEntityManager().remove(getEntityManager().merge(parent));

例外:

Caused by: javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`control`.`children`, CONSTRAINT `FK_CHILDREN_COUNTRY_ID` FOREIGN KEY (`COUNTRY_ID`) REFERENCES `countries` (`ID`))
Error Code: 1451
Call: DELETE FROM PARENT WHERE (ID = ?)
bind => [1 parameter bound]
Query: DeleteObjectQuery(com.frys.model.Country[ id=2 ])
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl$1.handleException(EntityManagerSetupImpl.java:692)
at org.eclipse.persistence.transaction.AbstractSynchronizationListener.handleException(AbstractSynchronizationListener.java:275)
at org.eclipse.persistence.transaction.AbstractSynchronizationListener.beforeCompletion(AbstractSynchronizationListener.java:170)
at org.eclipse.persistence.transaction.JTASynchronizationListener.beforeCompletion(JTASynchronizationListener.java:68)
at com.sun.enterprise.transaction.JavaEETransactionImpl.commit(JavaEETransactionImpl.java:452)
... 86 more

先感谢您!

4

2 回答 2

5

问题是上面代码CascadeType.DELETE中暗示的问题CascadeType.ALL适用于 EntityManager 中的对象,但不一定适用于数据库。配置 JPA 以生成 ddl 文件。看一下ddl文件,你会注意到ON DELETE CASCADE没有添加到约束中。添加ON DELETE CASCADEddl文件中的实际 SQL,然后从 ddl 更新您的数据库架构。这将解决您的问题。

链接显示如何在 MySQL中使用ON DELETE CASCADEon 。CONSTRAINT您在约束上执行此操作。您也可以在CREATE TABLEorALTER TABLE语句中执行此操作。JPA 很可能在ALTER TABLE语句中创建了约束。只需添加ON DELETE CASCADE到该声明。

请注意,一些 JPA 实现者确实为此功能提供了一种方法,因此使用风险自负。

于 2013-10-13T02:02:12.237 回答
1

您的子实体应该引用父级而不是国家级。也许是错字?您似乎没有在任何地方调用实体管理器删除,因此当您调用合并时,此时您的父级包含什么。这可以解释为什么您的 ORM 首先发出删除。

另外作为旁注,您的映射似乎有点混乱。在您的双向关系中,您已将父级映射为非所有者(使用 mappedBy),并且您还在那里提供了一个不必要的 JoinColumn。你必须给出这样的映射:

Parent
.......
@OneToMany (mappedBy = "parent", orphanRemoval = true, cascade={CascadeType.ALL}, targetEntity = Children.class)
private List <Children> children;
.........

Children
......
@ManyToOne(targetEntity = Parent.class, cascade = CascadeType.ALL)
@JoinColumn(name = "parent_id")
private Parent parent;

据我了解,您已将您的关系建模为父子对象,并且当您在父对象上调用实体管理器删除时,您希望您的 ORM 自动调用集合中其他子对象的删除。CASCADE 选项正是为此而生的。此外,ORM 将从您的映射中推断出要发送到数据库的删除命令的正确顺序,即应先删除子级,然后再删除父级,以避免任何外键约束。但是,如果您的父母也被用作其他实体中的外键,那么数据库将抱怨外来约束。

于 2013-10-13T04:12:52.770 回答