Brief
I am wondering what I should do as I have read many articles trying to understand this, including many SO questions. Nothing I have read has quite hit the nail on the head with this one.
I want to know what happens when a database is defined with cascade rules as well as the application since this will define whether I should take the following approach or another.
Example tables
create table foo(
id int unsigned not null auto_increment,
primary key(id)
);
create table bar(
id int unsigned not null auto_increment,
foo_id int unsigned not null,
primary key(id),
foreign key(foo_id) references foo(id) on delete cascade on update cascade
)
Example classes
@Entity
@Table(name = "foo")
public class Foo {
private int id;
private List<Bar> bars;
@Id
@GeneratedValue
@Column(name = "id")
public int getId() {
return id;
}
@OneToMany(mappedBy = "foo", cascade = {CascadeType.ALL})
public List<Bar> getBars() {
return bars;
}
public void setId() {
this.id = id;
}
public void setBars(List<Bar> bars) {
this.bars = bars;
}
}
@Entity
@Table(name = "bar")
public class Bar {
private int id;
private Foo foo;
@Id
@GeneratedValue
@Column(name = "id")
public int getId() {
return id;
}
@ManyToOne
@JoinColumn(name = "foo_id", nullable = false)
public getFoo() {
return foo;
}
public void setId(int id) {
this.id = id;
}
public void setFoo(Foo foo) {
this.foo = foo;
}
}
Questions
If I now call a delete operation (be it through EntityManagerFactory
or SessionFactory
) on a Foo
object, which of the following will occur?
The hibernate operation will delete all records in the
bar
table whose foreign key is that ofFoo
'sfoo_id
and then delete theFoo
record.The hibernate operation will delete all corresponding
Bar
records that have been loaded into session cache (which may or may not be allbar
records that exist in the actual database) and then delete theFoo
record (the database cascade rule will then delete any remainingbar
records).The hibernate operation will attempt to delete the
Foo
record first and if database failure then do one of the aforementioned steps.Something else happens for which I have not considered, if so what?
Considering the following dilemna assumptions, what is the best approach?
Dilemna
If 1 is true then it would suggest:
A) Define cascade rule in database only. Be sure to remove bars
from the object in the application so they are not left detached from the database (as the database will delete their records) then make the call to delete foo
.
OR
B) Define cascade rule in application only since it will manage the database integrity thoroughly.
NOT
C) Define cascade rules in both, since each achieve the desired result making the other a waste of processing.
If 2 is true then it would suggest:
Define cascade rules in both database and application so that Hibernate can take care of managing its entities and the database can clean up after since the application is not guaranteed to remove all the bar
records.
If 3 is true then it would suggest:
Define cascade rules in both database and application since Hibernate appears to support the cascade rule already being defined at the database level.
If 4 is true then it would suggest:
This question is even more important as I have missed something fundamental!
Edit: Add articles I have read...
Related articles
Conflicting views for database, application or both:
SO - should-i-let-jpa-or-the-database-cascade-deletions
Conflicting views for database or application:
SO - cascading-deletes-updates-using-jpa-or-inside-of-database
This article sheds light on what JPA providers actually do (though it should be noted that they use OpenJPA provider for their proof of operations):
It states that:
The cascading of remove and persist operations applies also on those entities that have not been loaded yet. It even passes through them to other entities, potentially traversing through whole object graph.
It goes on to state:
The cascading of refresh, merge and detach passes only through entities that are already loaded.
This would mean that proposed process 2 is not true.