ObjectDB ObjectDB

Object DB vs EclipseLink/TopLink: Unloaded relationships in detached entities

#1

This topic is for those considering migrating from EclipseLink JPA or TopLink to ObjectDB JPA.

This concerns a huge "gotcha" that other assessing migrating from and EclipseLink-based JavaEE web application to ObjectDB may encounter, and so far I am not sure what the best solution for my case is, only what the problem statement and options are. At first I was convinced that this involved either an ObjectDB bug or departure from the JPA spec by ObjectDB, but thanks to insistence and persistence from ObjectDB support I now concede the difference is due to an extending "feature" of EclipseLink (and TopLink before it). To explain this properly (and how it may impact on your ObjectDB project and on your EclipseLink to ObjectDB migration) I have to refer to some external EclipseLink/TopLink forum material.

On running a large existing web application on Glassfish3.0.1 for the first time successfully (i.e. it loaded) with ObjectDB, I was horrified to find that all of my collection relationships were null (not even just empty where appropriate), and on various pages I got NullPointerExceptions where non-null collection results (including non-null empty) were expected.

As explained to me by ObjectDB support, while the entities in a result set list from a JPQ query are initially managed (and so lazy loading would initially work), they become detached once the EntityManager under control of the container, and then in ObjectDB (but not in EclipseLink) lazy loading fails.

The 3 possible solutions in the ObjectDB case seem to be:

1. Use explicit FetchType.EAGER on all desired collections (which requires some re-coding and has performance consequences when large relationship hierarchies are involved) to ensure the desired collections are resolved already before detachment, losing all the benefits of lazy loading of course.

2. Perform the query within a @Stateful session bean with an extended EntityManager as described here:

blogs.oracle.com/enterprisetechtips/entry/extended_persistence_context_in_stateful

This however has the consequence of a long conversation until the stateful bean is released.

3. Use a FETCH JOIN as described here:

Detach JPA objects with lazy initialized properties

This has the big problem that one would need to tune queries for every preempted relationship, which for my application is impractical.

If you are previously an EclipseLink or TopLink user you may well be taking inadvertent advantage of feature that permits resolution of lazy loaded relationships outside a transaction, once detached, any you won't have needed any of the above required under ObjectDB operation !

The following quotes are from authoritative EclipseLink/TopLink gurus:

From Tom Ware at http://dev.eclipse.org/mhonarc/lists/eclipselink-users/msg05258.html:

Detached Objects get the connection need to traverse the LAZY relationship from the EntityManagerFactory and will able able to use it as long as the EntityManagerFactory is open. The connection used in not the transactional one and when you want to use the entity in a transaction it will have to be properly merged.

From chris_delahunt at http://www.java.net/node/706426:

In http://forums.oracle.com/forums/thread.jspa?messageID=1706796 it describes a feature of Toplink/EclipseLink that allows accessing untriggered lazy relationships after they are detached as long as the context is still avalable, which is what you are encountering. As long as the Entity is not serialized, and the connections are still available, you should still be able to get the referenced person entity.

From http://forums.oracle.com/forums/thread.jspa?messageID=1706796:

I am testing features of detached entities with a standalone application, and particularly with lazy loading association.

It seems that it is very difficult to "completely" detache an entity of a standalone application with TopLink. Even if I close the entity manager or the entity manager factory after having detached the entity, the detached entity finds how to load the entities of the lazy loading association from the database, when it needs it (without any merge call).

From doug clarke http://forums.oracle.com/forums/thread.jspa?messageID=1706796:

This is a special feature of TopLink's implementation where the detached instances created from non-tx reads still have access in their proxies to retrieve additional dettached instances. If the object was detached through serialization this would not be possible.
..
If you would like TopLink Essentials to not process lazy relationships after the EM has closed I would recommend filing an enhancement request in GlassFish.

The upshot for ObjectDB users is that you may have to undertake significant recoding of your web application and substantial additional entity management to use your application with ObjectDB (or in my case so far just to even try it out on my existing large web application). This is a non trivial matter to say the least.

Hoping this helps somebody,

Webel

 

edit
delete
#2

I have suggested or rather insist that the current ObjectDB Java EE tutorials at http://www.objectdb.com/tutorial/jpa/ee  are too simplistic (do not even contain any relationships) and do not adequately explore aspects like accessing lazy relationships when combined with Glassfish.

From http://en.wikiquote.org/wiki/Albert_Einstein:

"It can scarcely be denied that the supreme goal of all theory is to make the irreducible basic elements as simple and as few as possible without having to surrender the adequate representation of a single datum of experience."

There is a quote attributed to Einstein that may have arisen as a paraphrase of the above quote, commonly given as:

“Everything should be made as simple as possible, but no simpler.”

or

“Make things as simple as possible, but not simpler.”

 

edit
delete
#3

Having remarked on the ObjectDB JavaEE tutorials being too simple, it is worth nothing that in the JavaEE6 Tutorial:

- the word extended appears only once, and not in any way related to extended EntityManager or persistence context.

- "container detached" entities are not once discussed in the context of query results, although the tutorial uses Glassfish.

To find any reference to the matter one has to examine the JPA2 spec Final:

7.6 Container-managed Persistence Contexts
When a container-managed entity manager is used, the lifecycle of the persistence context is always
managed automatically, transparently to the application, and the persistence context is propagated with
the JTA transaction

A container-managed persistence context may be defined to have either a lifetime that is scoped to a single
transaction or an extended lifetime that spans multiple transactions, depending on the PersistenceContextType
that is specified when its entity manager is created. This specification refers to
such persistence contexts as transaction-scoped persistence contexts and extended persistence contexts
respectively.
The lifetime of the persistence context is declared using the PersistenceContext annotation or
the persistence-context-ref deployment descriptor element. By default, a transaction-scoped
persistence context is used.
Sections 7.6.1 and 7.6.2 describe transaction-scoped and extended persistence contexts in the absence of
persistence context propagation. Persistence context propagation is described in section 7.6.3.
Persistence contexts are always associated with an entity manager factory. In the following sections,
"the persistence context" should be understood to mean "the persistence context associated with a particular
entity manager factory".

7.6.1 Container-managed Transaction-scoped Persistence Context
The application can obtain a container-managed entity manager with transaction-scoped persistence
context bound to the JTA transaction by injection or direct lookup in the JNDI namespace. The persistence
context type for the entity manager is defaulted or defined as PersistenceContext-
Type.TRANSACTION.
A new persistence context begins when the container-managed entity manager is invoked[76] in the
scope of an active JTA transaction, and there is no current persistence context already associated with
the JTA transaction. The persistence context is created and then associated with the JTA transaction.
The persistence context ends when the associated JTA transaction commits or rolls back, and all entities
that were managed by the EntityManager become detached.
If the entity manager is invoked outside the scope of a transaction, any entities loaded from the database
will immediately become detached at the end of the method call.

7.6.2 Container-managed Extended Persistence Context
A container-managed extended persistence context can only be initiated within the scope of a stateful
session bean. It exists from the point at which the stateful session bean that declares a dependency on an
entity manager of type PersistenceContextType.EXTENDED is created, and is said to be bound
to the stateful session bean. The dependency on the extended persistence context is declared by means
of the PersistenceContext annotation or persistence-context-ref deployment descriptor
element.

The persistence context is closed by the container when the @Remove method of the stateful session
bean completes (or the stateful session bean instance is otherwise destroyed).

 

edit
delete
#4

Thank you very much for summarizing this topic so clearly.

It seems that implementing a similar extension in ObjectDB may be a good idea.

This feature request has just been added to the issue tracking.

ObjectDB Support
edit
delete
#5

The associated feature request is: 

Navigation through lazy loading from Detached Objects

 

edit
delete

Reply

To post on this website please sign in.