2

I have one many-to-many relationship in my model. There are two entities, Emergencies and Crews (crews can attend many emergencies, and vice versa). Code parts responsible for the relationship look as follows:

@JoinTable(name = "CREWS_ON_EMERGENCIES", joinColumns = {
    @JoinColumn(name = "EMERGENCY_ID", referencedColumnName = "EMERGENCY_ID", nullable = false)}, inverseJoinColumns = {
    @JoinColumn(name = "CREW_ID", referencedColumnName = "CREW_ID", nullable = false)})
@ManyToMany(fetch= FetchType.EAGER)
private Collection<Crew> crewList;

and

@ManyToMany(mappedBy="crewList", fetch= FetchType.EAGER)
private Collection<Emergency> emergencyList;

Crew is a dependent entity -- an emergencyList is updated when I add new Emergency with list of crews attended.

Actually, the database is updated fine, and new records appear in the CREWS_ON_EMERGENCIES table right after the transaction is closed. But if add a new emergency and then display a list of all crews and emergencies they have attended, the last emergency will not be displayed (obviously, "emergencyList" is out of date). It will appear only when I restart a server (Tomcat) or in debug mode.

Emergency save() code:

 @Transactional
public void save(Emergency e) {
    entityManager.persist(e);
    entityManager.flush();
}

Selected crews are added automatically in the collection crewList by Spring MVC.

Does anyone know why it happens in a way like this and what is the solution?

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
phil_g
  • 516
  • 6
  • 13

1 Answers1

1

I see two potential problems here:

  • your code doesn't maintain both sides of the bidirectional association. If a crew is added to an emergency, the emergency should also be added to the crew (and vice-versa). JPA doesn't maintain the coherence of the object graph for you.
  • if you need to restart Tomcat to see changes, it means that the entity manager is never closed and reopened, and its cache of entities does still contain entities that have been loaded in a previous transaction. There must be something wrong with the way you use the entity manager. Are you using the transactional and JPA support offered by Spring.

Side note: when I see that EAGER is used on both sides of a many-to-many association, I immediately think: "this app will be veeeeery slow". The load of an emergency will load all its crews, which will load all their emergencies, which will load all their crews... recursively. You could load half of the database like that.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Thank you for the fast response! I've added following lines into my controller to maintain the crews and it's worked! `for(Crew c: emergency.getCrewList()){ c.getEmergencyList().add(emergency); crewDao.merge(c); }` – phil_g Jan 05 '12 at 11:04
  • considering the EAGER fetching - yes, maybe the app is a bit slow, but I had weird errors, so it didn't work. Maybe I've messed something but to be honest a have no time to go deeper now. – phil_g Jan 05 '12 at 11:09
  • Oh, sorry for my inattention. Adding a piece of code I've described above creates a new problem. Every new emergency is created twice. There's no decision yet. – phil_g Jan 05 '12 at 12:29