Monday, April 19, 2010

When architecting an RIA (aka Web 2.0) application, you have to decide how do you implement the persistence layer. Using the ORM is a standard nowadays, so it's given. Question as to which ORM to use, got easier with strong acceptance of the Sun's JPA standard by the industry. But, how do you apply ORM in an RIA application is not a question with just a one obvious answer. On one side, the choice of the framework (and the architecture with it). This is presented in section 2. Section 3 presents another aspect of persistence layer: session management, that is how you actually use ORM to persist detached objects (detached, because they are received from outside of the application, namely from the client, for example a Flex client).

2. ORM in an RIA Application

Popular options are listed below. Each with advantages and disadvantages.

2.1. Just-JPA Approach:

LCDS, BlazeDS or another Flex remoting framework

JPA (in general: ORM) on the server-side, with an object mapper like Dozer

Pros and Cons:

Pro: Simple and a popular choice.

Con: Doesn't let you take advantage of ORM's lazy loading and lazy initialization.

2.2. LCDS with Built-In Hibernate Adapter:

This solution requires you to purchase a commercial heavy-duty Flex remoting framework Adobe LCDS (LiveCycle Data Services). If you go this way, to integrate it with persistence layer, you create a Hibernate assembler class on the server (Java) and point the LCDS destination to it, as described here.

Provides a complete open-source solution. Described in a nutshell in comment to this article. More complete information, and a comparison with LCDS-with-Hibernate-assembler option, can be found in this article by the same person (as the comment), William Drai. This article has also more general, highly useful, background on the topic as a whole.

Pros and Cons:

Pro: open-source; no vendor lock-in.

Cons: unknown

3. Persisting Detached Objects

The three most common applicable persistence design patterns are (as described by Hibernate documentation):

session per requestThe most common solution. A single Session and a single database transaction implement the processing of a particular request event. Do never use the session-per-operation anti-pattern.

session per conversationOnce persistent objects are considered detached during user think-time and have to be reattached to a new Session after they have been modified.

session-per-request-with-detached-objectRecommended. In this case a single Session has a bigger scope than a single database transaction and it might span several database transactions. Each request event is processed in a single database transaction, but flushing of the Session would be delayed until the end of the conversation and the last database transaction, to make the conversation atomic. The Session is held in disconnected state, with no open database connection, during user think-time.

Let's assume we have an application an RIA with stateless EJB's on the server side. Each request gets a new EntityManager injected. I suggest the following approach to implement session-per-request:

if we receive a new object, persist it using
entityManager.persist(entity)

if we receive an object, that is already in the database, use
entityManager.merge(entity)

There is one narrow case, when this wouldn't work as expected: when we have a bidirectional association between Invoice and InvoiceDetail and we receive and invoiceDetail with the field invoice set to null. If we apply the method as above, the merge() will reset the invoice in invoiceDetail to null, while the field invoiceDetails in invoice object will continue pointing to invoiceDetail. However, I consider this not a practical case.

4. Conclusion
So, a simple starting point that I recommend for your RIA application is to use just JPA with a session-per-request persistence pattern. It can be as simple as: