Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I keep entities (or their associations) attached to the current persistence context across multiple requests (using Wicket & JPA)?

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?

like image 420
pbitty Avatar asked Aug 15 '11 20:08

pbitty


People also ask

What are the 4 different states of entity in the persistence context?

persistence. Entity . Basically, there are 4 states of an Object in JPA and these are New (Transient), Persistent (Managed), Detached (Unmanaged) and Removed (deleted).

What is persistence context and EntityManager?

An EntityManager instance is associated with a persistence context. A persistence context is a set of entity instances in which for any persistent entity identity there is a unique entity instance. Within the persistence context, the entity instances and their lifecycle are managed.

Where is persistence context used in JPA data spring configuration?

The persistence context is the first-level cache where all the entities are fetched from the database or saved to the database. It sits between our application and persistent storage.

What do we mean by an extended persistence context?

JBoss EJB 3.0 allows you to define long-living EntityManagers that live beyond the scope of a JTA transaction. This is called an Extended Persistence Context. When you specify that an injected EntityManager is an extended persistence context, all object instances remain managed.


1 Answers

I cases like this I usually create a DTO keeping all the data I need to create an entity. If you need to reference existing entities - pass them to your forms/panels as separate models. When the form is submitted you can then:

  • perform the validation
  • create a new entity from DTO that was edited
  • inject references to other entities that you have stored in those separate LDM models.
  • persist the entity.

It's a bit of hassle but does actually work.

Conversations spanning multiple requests are not available in pure wicket and probably will never be - this is not wicket's area.

Seam supports long conversations and it does support wicket (I have never used seam - I cannot advice you on this one).

like image 78
lgawron Avatar answered Nov 01 '22 11:11

lgawron