Question

I am looking for help because when when I try to delete an entity that has OneToMany relation I get this error while loading the page with the List:

MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails

Of course I understand it is connected to Cascade deletion of children, but I don´t know where I am doing it bad.

Parent entity part relative to the relation with Children:

@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;
...
}

Children entity part relative to the relation with Parent:

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

JSF button to delete the entity:

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

Bean:

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

Exception:

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

Thank you in advance!

Was it helpful?

Solution

The issue is that CascadeType.DELETE which is implied by CascadeType.ALL in your code above applies to the objects in the EntityManager, but not necessarily the database. Configure JPA to generate a ddl file. Take a look at the ddl file, you'll notice that ON DELETE CASCADE is not added to the constraint. Add ON DELETE CASCADE to actual SQL in the ddl file, then update your database schema from the ddl. This will fix your problem .

This link shows how to use ON DELETE CASCADE on for CONSTRAINT in MySQL. You do this on the constraint. You can also do it in a CREATE TABLE or ALTER TABLE statement. It's likely that JPA creates the constraint in an ALTER TABLE statement. Simply add ON DELETE CASCADE to that statement.

Note that some JPA implementors do provide a means for this functionality, thus use at your own risk.

OTHER TIPS

Your children entity should be having a reference to parent and not country. Perhaps a typo? You did not seem to have called entity manager delete anywhere so when you call merge then at that point what does your parent contains. This could explain why your ORM is issuing a delete in first place.

Also as a side note, your mappings seems to be bit confusing. In your bidirectional relationship, you have mapped parent as non-owner (using mappedBy), and you are also giving a JoinColumn there which is not necessary. You have to give mappings like this:

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;

From what I understand, you have modeled your relationship as parent child and when you call entity manager delete on parent, you want your ORM to automatically call delete on other children objects in the collection. The CASCADE option in exactly for this. Also the ORM will infer the right sequence of delete commands to be sent to the database from your mappings i.e., the children should be deleted first and then parent to avoid any foreign key constraint. If however your parent too is used as a foreign key in some other entity, then the database will complain for foreign constraint.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top