I recently asked a question on Stack Overflow regarding the lifecycle of entities, however it's been suggested that this community might be in a better position to help me out. I'm using an extended persistence context contained in a stateful session bean to maintain state between client calls. The stateful session bean is being accessed from stateless beans that are wrapped using resteasy. This seems to work OK, up to the point that an exception is encountered. After an exception however, the entities managed by the persistent context become detached, which means next time I try to use them, I get hibernate exceptions refering to 'detached entity passed to persist'.
Is it expected behaviour that when exceptions are encountered objects from an extended persistence context will become detached? If so, is there any way to stop the entities from becoming detached (possibly by marking them as 'readonly')?
In the stack overflow question, I give an example that shows that I can alter the behaviour, by either calling out to or not calling out to the stateful bean before throwing the exception. Could somebody explain why this makes a difference? I suspect I'm doing something wrong but I can't figure out why the entities are becoming detached.
From the JPA 2.0 specification section 3.3.2:
For both transaction-scoped and extended persistence contexts, transaction rollback causes all pre-existing managed instances and removed instances to become detached. The instances’ state will be the state of the instances at the point at which the transaction was rolled back. Transaction rollback typically causes the persistence context to be in an inconsistent state at the point of rollback. In particular, the state of version attributes and generated state (e.g., generated primary keys) may be inconsistent. Instances that were formerly managed by the persistence context (including new instances that were made persistent in that transaction) may therefore not be reusable in the same manner as other detached objects—for example, they may fail when passed to the merge operation.
It is expected that a transaction rollback will cause the managed objects (associated with the extended persistence context) to be detached.
Also note more details about this in JPA specification section 7.9.2
The Provider has no knowledge of the distinction between transaction-scoped and extended persistence contexts. It provides entity managers to the container when requested and registers for transaction synchronization notifications.
... skipping other details
* When the JTA transaction rolls back, the provider must detach all managed entities.
Have you tried merging the detached entities back in? That is one way to restablish the application state after a transaction rollback.
Thanks Scott, it's really good to know that this is expected behaviour and something that needs to be dealt with. It sounds like the best approach is to minimise the number of exceptions that are allowed to cross the service boundary in order to prevent unnecessary detachments, combined with the @ApplicationException annotation that James mentions in your linked post, where appropriate.
Is there a way to know if an entity is detached, other than to try and persist it? So, for example if I have three service calls:
1. Reads information into persistent context + creates a new entity
2. Tries to create a new entity, referencing an existing one but this fails (resulting in everything becoming detached0
3. Tries to create a new entity, referencing an existing one, which would succeed however the dependent entity is detached.
From what you've said, the entities in the context are detached during the rollback of the second call. Do I need to store information as a result of the rollback so that when the third call comes in I know that I need to reread / merge the entities, or is this information somehow available through the entity manager? In other words, given an entity and an entity manager is there a way to tell if the entity manager is currently managing the entity, or if the entity has become detached (as a result of a previous issue)? Or would you suggest calling merge rather than persist when creating entities that have dependencies on existing (possibly detached) entities from the extended persistence context?