I'm seeing a lot of similar questions, but haven't found something conclusive that brings it together.
When using JPA, if you have a @OneToMany relation it can be specified to cascade the REMOVE
operation. At the same time, foreign keys can be specified in the database with an action to take if the key base row gets deleted.
JPA example:
@Entity
public class Parent {
@Id
private Long id;
@OneToMany(cascade = {CascadeType.REMOVE})
private List<Child> children;
// getters, setters...
}
@Entity
public class Child {
@Id
private Long id;
@ManyToOne(optional = false)
@JoinColumn(name = parent_id, nullable = false)
private Parent parent;
// getters, setters...
}
In the database, the Child
table would then have a column parent_id
with a foreign key constraint to the Parent
's id
column.
Some actions possible on that foreign key constraint for cascading on delete are delete
, set to null
and do nothing
. This gives the following combinations of scenarios.
JPA | cascade | no cascade | | remove | remove | DB FK | | | -----------+---------+------------| delete | A | D | -----------+---------+------------| set null | B | E | -----------+---------+------------| do nothing | C | F | -----------+---------+------------+
- A: Cascade remove call on parent in JPA, delete children in database on deletion of parent row they have a foreign key to.
- B: Cascade remove in JPA, set foreign key column in Child table to null in database on parent delete. The
nullable
in @JoinColumn and/oroptional
in@ManyToOne
probably need to be true/false in this case. - C: Cascade remove in JPA, do nothing in the database on a foreign key removal.
- D: Don't cascade remove in JPA, cascade delete of parent in database.
- E: Don't cascade remove in JPA, set foreign key column in Child table to null in database on parent delete.
- F: Don't cascade remove in JPA, do nothing n the database on a foreign key removal.
So, questions about this.
Which of these scenarios leads to exceptions? If figure C would. If you remove a Parent
instance via an EntityManager
, the call is first done on that instance and then cascaded to the Child
instances in the collection property. But trying to remove a parent from the database without first removing related children leads to foreign key violations. Is this correct? Are there other faulty scenarios? Woud A cause issues with trying to remove entities from persistence that have already been removed from the underlying DB?
Which leave the EntityManager cache in an inconsistent state with the database? I reckon it's D and E. In these cases you would have to call remove()
for the instances in the child list yourself.
Which setup should you use to enforce data consistency in both the JPA layer and on the database? Will A do the trick? I think B could also work since the database itself will set the foreign key columns to null on deleting a parent (no longer violating constraints) and JPA can then remove the child instances.