Reputation: 27266
I have two entity classes A and B that exist in a bidirectional one-to-many relationship respectively.
A.java:
@OneToMany(cascade = CascadeType.ALL, mappedBy = "aId",
fetch=FetchType.EAGER, orphanRemoval=true)
private Set<B> bCollection = new LinkedHashSet<B>();
B.java
@JoinColumn(name = "A_ID", referencedColumnName = "ID", nullable=false)
@ManyToOne(optional = false)
private A aId;
In a simple console application I obtain a specific A row from the database and try to delete one of its detail B rows (at random) but JPA/Hibernate not only does remove the row - it doesn't even issue any DELETE statements towards the database. The only way to remove the B row is by removing the corresponding entity from the collection (LinkedHashSet) of A.java. So, while I have a workaround, I would like to understand why the below code fails, and fails quietly too!
public static void main(String[] args) {
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("testjpa");
EntityManager em = entityManagerFactory.createEntityManager();
EntityTransaction entityTransaction = em.getTransaction();
entityTransaction.begin();
A a = em.find(A.class, 1);
B b = getARandomChildOfA(a);
em.remove(em.merge(b)); // simple em.remove(b) doesn't work either
entityTransaction.commit();
em.close();
entityManagerFactory.close();
}
Upvotes: 2
Views: 7044
Reputation: 21145
JPA doesn't manage relations for you, so while you have called remove on b, a still has a reference to it. Since the reference has a cascade persist/merge set on it, it causes b to be resurrected in the context, undoing the remove.
You must maintain references to keep your model in sync with what you want in the database. It is good practice to null out references to objects you are removing and set back pointers unless you are sure you can deal with potential inconsistencies such as this.
Upvotes: 6