views:

137

answers:

1

Working with JPA / Hibernate in an OSIV Web environment is driving me mad ;)

Following scenario: I have an entity A that is loaded via JPA and has a collection of B entities. Those B entities have a required field.

When the user adds a new B to A by pressing a link in the webapp, that required field is not set (since there is no sensible default value).

Upon the next http request, the OSIV filter tries to merge the A entity, but this fails as Hibernate complains that the new B has a required field is not set.

javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value

Reading the JPA spec, i see no sign that those checks are required in the merge phase (i have no transaction active)

I can't keep the collection of B's outside of A and only add them to A when the user presses 'save' (aka entitymanager.persist()) as the place where the save button is does not know about the B's, only about A.

Also A and B are only examples, i have similar stuff all over the place ..

Any ideas? Do other JPA implementaions behave the same here?

Thanks in advance.

+1  A: 

I did a lot reading and testing. The problem come from my misunderstanding of JPA / Hibernate. merge() always does a hit on the DB and also schedules an update for the entity. I did not find any mention of this in the JPA spec, but the 'Java Persistence with Hibernate' book does mention it.

Looking through the EntityManager (and Session as fallback) API it looks as if there is no means of just assigning an entity to the current persistent context WITHOUT scheduling an update. After all, what I want is to navigate the object graph, changing properties as needed and trigger an update (with version check if needed) later on. Something i think every Webapp out there using ORM must do?

The basic workflow i 'm looking for:

  1. load an entity from the DB (or create a new one)
  2. let the entity (and all its associations become detached (as the EntitManager closes at the end of a HTTP request)
  3. when the next HTTP request comes in, work again with those objects, navigating the tree without fear of LazyInitExceptions
  4. call a method that persists all changes made during 1-3)

With the OSIV filter from spring in conjunction with an IModel implementation from wicket i thought i have archived this.

I basically see 2 possible ways out of it:

a) load the entity and all the associations needed when entering a certain page (use case), letting them become detached, adding/ changing them as needed in the course of several http requests. Than reattach them when the user initiates a save (validators will ensure a valid state) and submit them to the database.

b) use the current setup, but make sure that all newly added entities have all their required fields set (probably using some wizard components). i would still have all the updates to the database for every merge(), but hopefully the database admin won't realize ;)

How do other people work with JPA in a web environment? Any other options for me?

bert