I am working on a Wicket-based web app on Java EE.
I am trying to find a way to ensure that any entities used as model objects are always attached to the current EntityManager before Wicket tries to render any components. This way, when the components grab data from their model, the data can be lazily-loaded by the entity as needed.
There are lots of tutorials out there, and some posts on here, referring to LoadableDetachableModels (LDM) as the solution. This has worked for us when we don't need to keep any state in-between requests. In these cases, whenever the page is rendered, the LDM will load the most recent version of the required entity from the database.
However, there are times when a user needs to edit data in a stateful form via multiple steps before she saves the data, so the model needs to retain the entity in its 'unsaved' state. An LDM would effectively wipe out the user's changes on every step.
So far, we have been using a model that merges the entity with the persistence context when needed. Here is a simplified version:
public final class DetachableMergingModel<E extends Identifiable> implements IModel<E> {
private E entity;
private boolean attached = false;
public DetachableMergingModel(E entity) {
this.entity = entity;
}
@Override
public E getObject() {
if (!attached) {
attached = true;
// Non-transactional method merges entity with persistence context
// but does not flush any data to database
entity = getRepository().merge(entity);
}
}
return entity;
}
@Override
public void setObject(E entity) {
this.entity = entity;
}
@Override
public void detach() {
// This ensures that the next call to getObject() will merge the entity with
// the persistence context
attached = false;
}
/* ... */
}
Our EntityManager is injected by GlassFish and it spans a whole servlet request, so when an entity is attached to the persistence context, it will stay attached until after the page has been rendered.
This Model above takes care of situations where the entity is already persisted and is just being edited. Whenever a component on the page calls getObject() on this model, the Model will merge the entity with the persistence context, and we are free to navigate the whole object graph of the entity without throwing any LazyInitializationExceptions.
However, in a situation where the entity is new and has not been persisted, we cannot use this Model because the entity is not ready to be merged yet. This is often the case when the user is creating a new entity, and still needs to populate it with values via the form. In this case, we want to have the same freedom navigating the object graph of the entity (as some associations have already been set, such as the entity's parent), without fear of a LazyInitializationException.
A similar solution is described here (option #3), but it does not cover the 'new entity' use-case described above.
Has anyone come across this use-case? How did you solve it? Is there a better way to integrate Wicket with JPA than through custom IModel implementations?