3. Managed Entities & Lazy Loading
Managed Entities
Tide provides an integration between the LCDS-like concept of managed entities and the entity context.
All entities marked as [Managed] are considered as corresponding to Hibernate/JPA managed entities. It is possible to do the same by implementing IEntity and extending EventDispatcher. The managed entities delegate all operations on their getters/setters to the context to which they belong. That allows the context to track changes made on them.
From the Flex documentation of IManaged:
private var _property:String; public function get property():String { return Manager.getProperty(this, "property", _property); } public function set property(value:String):void { Manager.setProperty(this, "property", _property, _property = value); }
The Tide Manager implementation itself forwards the getters/setters to the EntityManager/Context containing the entity.
It is important to note that the IManaged interface is not sufficient to have correct Tide managed entities because Tide needs that the entities implement a few functionalities that are not provided by the standard Flex IManaged objects.
| The recommended way for getting Tide enabled managed entities is to generate them with Gas3 using the tide="true" option. |
<gas3 outputdir="as3" tide="true"> <classpath> <pathelement location="classes"/> </classpath> <fileset dir="classes"> <include name="test/granite/ejb3/entity/**/*.class"/> </fileset> </gas3>
Important Things on ID/UID
In a typical Flex/app server/database application, an entity lives in three layers:
- the Flex client
- the Hibernate/JPA persistence context
- the database
During the entity life, the only invariant is the id. The id reliably links the different existing versions of the entity in the three layers. When updating existing entities coming from the database, there are, in general, no problems because the id is defined and is maintained in the three layers during the different serialization/persistence operations.
A problem arises when a new entity is being created in any of the two upper layers (Flex/JPA). The new entity has no id until it has been persisted to the database. This means that between the initial creation and the final stored entity, the id has changed from null to a real value.
It is thus impossible to have a reliable link between the original entity that has been created and the entity that has been stored. This is even more complex if you try to add two or more new entities to a collection because, in this case, there will be absolutely no way to determine which one has been persisted with which id because they all had null ids at the beginning.
The problem already exists outside of Flex when you use a database generated id with Hibernate/JPA. The most common solution is to have a second persisted id, the uid, which is created by the client and persisted along with the entity.
With Flex, we have the same problem because the entities are often serialized/deserialized between Flex and the server, so we cannot check object instances equality. Moreover, Flex components themselves (DataGrids, Lists, ...) use the uid property as an entity identifier to correctly manage different object instances.
When there is a uid field in the Java entity, the Gas3 Tide template will generate a uid property on the AS3 object. In other cases, the Tide template tries to build a convenient uid property from the entity id. This second mode is, of course, vulnerable to the initial null id problem.
In conclusion, the recommended approach to avoid any kind of subtle problems is to have a real uid property which will be stored in the database but is not a primary key for efficiency concerns. If it is not possible to add a uid property due to a legacy database schema or Java classes, it will work most of the time but you will then have to be very careful when creating new entities from Flex.
Automatic Lazy Loading of Collections
All uninitialized lazy collections coming from the server are transparently wrapped on the Flex side by the Tide context in a PersistentCollection. This collection can be used as a data provider for any Flex component which supports the ItemPendingError functionality (DataGrid and List do). When data is requested by the UI component, the collection asks the server for the real collection content. This lazy loading functionality is completely automatic but will happen only if the collection is bound to a UI component.
Note that it is recommended, when possible, to use lazy loading in the context of a server conversation/extended persistence context. In this way you are assured that the collection elements will come from the same persistence context as the owning entity and the corresponding object graph.
Outside of a conversation, Tide will try different means to determine the correct EntityManager/Hibernate session to use. The whole collection and owning entity are then retrieved from a newly created persistence context. If you have a deep object graph, it will then be possible to get entities from different persistence contexts in the same client context, and it can lead to issues with optimistic locking/versioning.
Manually Fetching Lazy Collections
Tide makes use of the standard Flex ItemPendingError to handle lazy loading. It is thus possible to manually fetch the content of the collection. This is described in the Flex documentation here.
