failed to lazily initialize a collection
quilian Apr 25, 2007 11:55 AMHello again!
I managed to get my other problems working by using a SMPC (thanks pete).
however i now stumble accross the 1:n relationship of my entities Benutzer and Gruppe.
I declared the Benutzer as following:
@Entity @Name("benutzer") @Table(name = "benutzer") public class BenutzerImpl implements Serializable, Benutzer { private static final long serialVersionUID = -2113540391643036310L; private Long id; private Integer version; private String name; GruppeImpl gruppe; @Logger Log log; @Override public boolean equals(Object object) { if (object instanceof BenutzerImpl) { BenutzerImpl other = (BenutzerImpl) object; return (this.getId()==other.getId()); } return false; } @Id @GeneratedValue public Long getId() public void setId(Long id).. @Version public Integer getVersion()... @SuppressWarnings("unused") private void setVersion(Integer version).. @ManyToOne(optional = true) @JoinColumn(name = "gruppe", nullable = true) public GruppeImpl getGruppe() { return gruppe; } @Transactional public void setGruppe(GruppeImpl aGruppe) { if (gruppe != null) { gruppe.removeBenutzer(this); gruppe = aGruppe; if (gruppe != null) { gruppe.addBenutzer(this); } } else { gruppe = aGruppe; } } }
and the Gruppe like that:
@Entity @Name("gruppeImpl") @Table(name = "gruppen") public class GruppeImpl implements Serializable, Gruppe { @Logger Log log; private static final long serialVersionUID = 2106790568007992821L; private Long id; private Integer version; private String name; private Boolean status; private List<BenutzerImpl> someBenutzer; @Override @Transient public boolean equals(Object object) { if (object instanceof GruppeImpl) { GruppeImpl other = (GruppeImpl) object; return (this.getId()==other.getId()); } return false; } @OneToMany(mappedBy = "gruppe") @Transactional public List<BenutzerImpl> getBenutzer() { return someBenutzer; } public void setBenutzer(List<BenutzerImpl> newBenutzerList) { this.someBenutzer = newBenutzerList; } @Transactional public void addBenutzer(BenutzerImpl benutzer) { if (this.someBenutzer == null) { this.someBenutzer = new ArrayList<BenutzerImpl>(); } if (!this.someBenutzer.contains(benutzer)) this.someBenutzer.add(benutzer); } @Transactional public void removeBenutzer(BenutzerImpl benutzer) { if (this.someBenutzer == null) { return; } this.someBenutzer.remove(benutzer); } ... }
The whole stuff in english:
If the Benutzer gets a new Gruppe he must update the corresponding List Gruppe.getBenutzer(). Else the java object gruppe doesnt know that something happened to him. Therefore i extended the simple setter Benutzer.setGruppe() to remove/add from old/new Gruppe.Im not sure if hibernate or javax or anything else could possibly do that for me, knowing that i want a 1:n relationship. i only do the update if the property gruppe is already set, because hibernate itself calls the getter on initialization of the Benutzer.
I also annotated the functions setGruppe, addBenutzer and removeBenutzer as @Transactional, because i want the operation to be in one transaction, hence rolled back completely if an error occurs. is that correct?
If i choose another Gruppe and submit the form i get:
17:35:52,468 ERROR [LazyInitializationException] failed to lazily initialize a collection of role: com.mobilanten.mowita.werkbank.GruppeImpl.benutzer, no session or session was closed org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.mobilanten.mowita.werkbank.GruppeImpl.benutzer, no session or session was closed at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358) at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:350) ...
I debugged and found out that both the new and the old Grupp have a session attribute with two different persistance contexts that referer to the same hibernate.session. By the time of execution of Benutzer.setGruppe() the session of the old Gruppe is marked as closed.
Why are there 2 PCs ? i thought there'd only be this one (components.xml)
<core:managed-persistence-context name="mowitaEntityManager" auto-create="true" persistence-unit-jndi-name="java:/mowitaWerkbankEntityManagerFactory"/>
injected like that (GruppenManager and BenutzerManager):
@In private EntityManager mowitaEntityManager;
I thought the SMPC would be application global....
Thanks for any help!
Tobias Kilian