I have two entities like the following:
@Entity
public class Trip {
@OneToMany(mappedBy = "trip", fetch = FetchType.LAZY)
private Set<Job> jobs = new HashSet<Job>();
}
@Entity
public class Job {
@ManyToOne(fetch = FetchType.LAZY)
private Trip trip;
}
The problem is that the mappedBy relationship behaves differently in different circumstances. Here is an example
EntityManager em1 = unit.createEntityManager();
EntityManager em2 = unit.createEntityManager();
// One EM starts transaction and stores a trip
em1.getTransaction().begin();
Trip trip = new Trip();
em1.persist(trip);
Long tripId = trip.getId();
assertThat(tripId).isPositive();
em1.getTransaction().commit();
// Then em2 starts different transaction
em2.getTransaction().begin();
// Looking up for the trip through clean em (cache is empty)
Trip em2Trip = em2.find(Trip.class, tripId);
Job job = new Job();
job.setTrip(em2Trip);
em2.persist(job);
// The em2Trip should not be updated
assertThat(em2Trip.getJobs()).hasSize(1);
em2.getTransaction().commit();
em1.getTransaction().begin();
Trip em1Trip = em1.find(Trip.class, tripId);
// fails here
assertThat(em1Trip.getJobs()).hasSize(1);
em1.getTransaction().commit();
The code above shows that if an entity is already loaded in the entity manager’s cache, the getter for the mappedBy relationship may return invalid results.
I have a proof it doesn’t work under JBoss either. The following code behaves differently depending on which entity manager is being used. The result is unpredictable.
Trip trip = em.find(Trip.class, tripId);
if (trip.getJobs().size() == 0) ...
Does this mean that the mappedBy automatically makes application buggy as soon as it is introduced and used?
P.S. I am not trying to abuse hibernate. I only want to find out if someone faced such a problem and how did they cope with it
Behavior you’re describing has absolutely nothing to do with associations; you would get the exact same results if you just tried to read / update simple POJO from two entity managers. Once your entity is associated with persistence context it will NOT be automatically refreshed from the database. This is a documented behavior – and in the vast majority of cases this is a DESIRED behavior.
As far as “keeping your application stable” goes:
refresh()method which you can invoke to reload entity state from the database.clear()method which will clear the persistence context completely thus preventing this issue as well. Use it sparingly and cautiously, though – invokingclear()withoutflush()will throw away all pending updates.