Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA relationship not getting updated when children are removed

Given the following scenario:

@Entity
public class A {
  @OneToMany(mappedBy = "a", cascade = CascadeType.ALL)
  private List<B> bList;
}

@Entity
public class B {
  @ManyToOne()
  @JoinColumn(name = "a_id", referencedColumnName = "id")
  private A a;

  @ManyToOne()
  @JoinColumn(name = "c_id", referencedColumnName = "id")
  private C c;
}

@Entity
public class C {
  @OneToMany(mappedBy="c", cascade=CascadeType.ALL, orphanRemoval=true)
  @CascadeOnDelete // eclipselink specific optimization annotation
  private List<B> bList;
}

In other words: both object A and object C contains a number of B objects.

When I remove a C object (technically, I am updating an object containing several C objects and using orphanremoval), I wish to remove all referenced B-objects, which works as expected with current annotations. However, the Entity manager doesn't seem to understand that object A lying in its cache now have lost some children. If I had an instance of A, I would of course have to update its bList manually, or do a new query to update it, but even newly fetched A-objects are still outdated. To reiterate:

  • C objects are removed.
  • Removal is cascaded to B objects with orphanRemoval.
  • bList in A objects cached in Entity Manager is not updated.
  • Manually purging Entity Managers cache makes it retrieve properly updated objects.

How can this be solved? I would expect either the entity managers to update its persistence context automatically, or making a cascade annotation available on @JoinColumn, but neither seems to be the case here.

EDIT: It seems that the problem lies in object C's bList not getting updated when object A's bList is updated (and thus cannot cascade changes). I have no idea why though.. Still note that I'm talking about the persistance context and not instantiated objects.

like image 227
Rasmus Franke Avatar asked Apr 26 '11 15:04

Rasmus Franke


1 Answers

JPA does not do relationship maintenence for you, the application must maintain them. That means when ever you delete an entity, the application is responsible for cleaning up any references to that entity. It is obvious when it is a foreign key relationship, as database constraints will usually cause an exception if it is not done. In the case of back references though where the relationship does not have a strict database constraint, users generally mistakenly believe that JPA will handle it - leaving the cache corrupted.

The way to handle it is to remove any references to C and B entities. In your object model, that means fixing A's bList to remove Bs. I have seen this handled through entity remove events or in application code. Since in this case, A does not have a foreign key, you could also refresh the affected A entities from the database after the delete has occured (ie after a flush or commit).

like image 109
Chris Avatar answered Oct 27 '22 11:10

Chris