Exception while lazily loading a collection from entity
I fear that I miss a very basic point, but I'm stuck at the moment, hopefully someone can point my eyes starring to hard at it to the right one... I try to go through my application setup step by step for make myself clear (hoping people won't get bored before they reach the end of the posting):
I have a session scoped CDI component serving as a handler for a JSF 2.0 view. It holds an entity manager, a list of objects and a special single object:
@Named
@SessionScoped
public class EventHandler implements Serializable {
@PersistenceContext
private EntityManager em;
private List<MyEvent> events;
private MyEvent currentEvent;
...
When the view requests the list for displaying a table, it fills the list by querying the database:
Query query = em.createQuery("select e from MyEvent e");
events = (ArrayList<MyEvent>) query.getResultList();
The view shows this in a data table and provides a link to an action method within the handler:
<h:dataTable value="#{eventHandler.events}" var="_var">
...
<h:commandLink action="#{eventHandler.linkAction(_var)}"> ... </h:commandLink>
The action method stores the reference:
public void setCurrentEvent(MyEvent currentEvent) {
this.currentEvent = currentEvent;
...
Within the entity used in the collection and references above, the开发者_如何转开发re'a relationship which gets loaded lazily by default:
@ManyToMany(mappedBy="supportedServices")
public Set<MyEntity> getSupportingEntities() {
...
Now, when being in the detail view and trying to access this relationship by doing:
#{eventHandler.currentEvent.supportingEntities...}
I get a org.hibernate.LazyInitializationException telling me that the session is closed.
Shouldn't the handler be able to load the requested relationship at a later point in the 2nd view, when the handler is session scoped and loaded the references via a query?
Hum, I think this is because the persistenceContext, event if it is a member of a session scoped bean, is not session scoped.
When the view is called the first time, a persistence context is created, the entities(events) are loaded and the datatable is populated. Then the persistence context is flushed, closed and the response is sent to the client. This all happen in the same http request.
But when you then call the details view, another http request is issued, and another persistence context is created, and your reference to "currentEvent" is no more attached to the last persistence context. Hence the LazyInitializationError (the entity must be managed to lazy load).
Solutions could be :
- Use an extended persistence context (explained here).
Eager fetch the relation :
@ManyToMany(mappedBy="supportedServices", fetch=FetchType.EAGER)
Merge the detached instance of currentEvent before using it in the details view :
entityManager.merge(currentEvent);
精彩评论