Reputation: 14737
I have three classes (A has many B, which has many C) :
class A {
@OneToMany (mappedBy="a", fetch = FetchType.LAZY, cascade=CascadeType.ALL)
public List<B> bs;
public List<B> getBs() {
return bs;
}
public void setBs(List<B> bs) {
this.bs = bs;
}
}
class B {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "a")
private A a;
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
@OneToMany (mappedBy="b", fetch = FetchType.LAZY, cascade=CascadeType.ALL)
public List<C> cs;
public List<C> getCs() {
return cs;
}
public void setCs(List<C> cs) {
this.cs = cs;
}
}
class C {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "b")
private B b;
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
}
I use Spring Data to handle delete. Here is what I am able to do successfully:
If I delete a single record B, this record is deleted and its associated C records are automatically deleted too.
If I delete a single record A, this record is deleted and its associated B/C records are automatically deleted too.
However, if I want delete A's B records (without delete A record) via the following:
public void deleteByA(A a) {
//em is EntityManager
Query q = em.createNamedQuery("delete from B where a = :a");
q.setParameter("a", a);
q.executeUpdate();
}
I always get the following error:
The DELETE statement conflicted with the REFERENCE constraint "FK_1pbkk0g3b9vnx7apvisddsh7e". The conflict occurred in database "mydb", table "dbo.C", column 'b'.
Is there any obvious place in the above I did wrong? What could be the possible problem?
Thanks for any input!!!
Upvotes: 1
Views: 2224
Reputation: 692121
The problem is simply that delete queries don't take the cascade annotations into account. They're low-level queries, translated to SQL and executed, but bypassing the session (i.e. if you delete an entity that is in the session, it won't be marked as deleted in the session) and the cascade mechanisms.
So, either you get the Bs and delete them by calling em.remove(), or you do as you would do with SQL: delete the Cs explicitely first, then delete the Bs, using delete queries. But once again, read the restrictions: delete queries can't use joins (unless the joins are in a subselect).
Here's the relevant documentation.
Upvotes: 2