Entity Persistence with dpHibernate – Overview

dpHibernate is an open source project that facilitates lazy loading of hibernate entities with BlazeDS and Flex.

Note:  If you’re not familiar with the dpHibernate project, it may to have a read of this overview post

The topic discussed here is currently only available on the changeMessaging branch of dpHibernate.  The code is available here:

http://dphibernate.googlecode.com/svn/branches/changemessaging

Recently I committed some changes to a new branch of the source which now allows persistence operations (Create, Update, Delete) on entities, using a few lines of code.

Eg:

public class SomePM {
    public void doSomeWork(author:Author) {
        author.name = “Josh Bloch”;
        author.age = 30;
        author.publisher = publishers.findByName(“AddisonLee”);
        author.save();
    }
    public function createNewAuthor():void {
        var newAuthor : Author = new Author();
        newAuthor.name = “Sondhiem”;
        newAuthor.age = 55;
        newAuthor.save();
    }
    public function deleteAuthor(author:Author):void
    {
        author.deleteRecord();
    }
}

This is similar to the entity persistence provided by LCDS, but without the exorbitant licensing fee!

The save() and deleteRecord() methods are made available through the new IUpdatableHibernateProxy interface. Generally, these would delegate work back to the HibernateUpdater class. Examples of this implementation are shown later.

This approach saves the process of having to write individual update services for each entity (which, often requires several methods for each field. Painful!)

Eg:

// Actionscript:
[Managed]
public class Author extends BaseEntity {
    public var id : int;
    public var name : String;
    public var age : int;
}
public class BaseEntity extends HibernateBean {
    public function save(responder:IResponder = null) : AsyncToken
    {
        return HibernateUpdater.save(this,responder);
    }
    public function deleteRecord(responder:IResponder=null) : AsyncToken
    {
        return HibernateUpdater.deleteRecord(this);
    }
}

From this, Author, and all other subclasses of BaseEntity inherit a save method (which handles both creates and updates of entities) and delete method.

Note, that should you wish to keep persistence methods out of your entity classes, the following is also valid:

[Managed]
public class Author implements IHibernateProxy {
    public var id : int;
    public var name : String;
    public var age : int;
    // IHibernateProxy impl. Excluded...
}

public class SomePM {
    public function updateAuthor(author:Author):void
    {
        HibernateUpdater.update(author);
    }
    // Or, for that matter...
    public function updateAnyEntity(entity:IHibernateProxy):void
    {
        HibernateUpdater.update(entity);
    }
}

Or, if you prefer a more dependency injection friendly implementation:

public class SomePM {
    [Inject] // Actual injection depends on your DI framework of choice.
    public var hibernateUpdater:IHibernateUpdater;

    public function updateAuthor(author:Author):void
    {
        hibernateUpdater.update(author);
    }
}

(Note, this would also work within the Author class itself, should you prefer)

The possibilities for implementation are pretty open, and not overly prescriptive from the dpHibernate framework. The only requirements in terms of your entity classes to facilitate persistence are that they are tagged [Managed] (or implement IManaged), and implement IHibernateProxy.

Nested properties and collections

Both nested properties and changes to collections are supported.

Eg:

Nested properties

public class SomePM {
    public function doSomeWork(book:Book):void
    {
        book.author.name=”newName”;
        book.save();
    }
}

Collections

public class SomePM {
    public function doSomeWork(author:Author,book:Book):void
    {
        author.books.addItem(book);
        author.save();
    }
}

A combination of both

public class SomePM {
    public function doSomeWork(author:Author,book:Book):void
    {
        author.books.addItem(book);
        book.title=”This is the new title”;
        author.save(); // Also persists the change to book.title,
        // as it's part of the author.books collection.
    }
}

Efficient .save()’s

When calling save() on an entity, the actual entity itself is not passed across to the update service. For complex entity trees with collections and nested hierarchies, serialization within the Flash player can be painfully slow.

Eg, consider the following common example:

[Managed]
public class Author extends BaseEntity {
    public var id : int;
    public var name : String;
    public var age : int;
    public var books : ArrayCollection;
}
[Managed]
public class Book extends BaseEntity {
    public var title : String;
    public var author : Author;
}

The Parent entity – Author, contains a list of children entities – books, each of which contains a reference back to it’s parent. These circular references are commonplace, and required in many scenarios by Hibernate.

If we were to use standard AMF serialization for this, the nested tree can get very deep very quickly, depending on the number of Books an Author has written. Additionally, this cost is completely unnecessary if the only thing changed on the Author is it’s name.

Also, given that dpHibernate facilitates lazy loading, it’s quite possible that the property Author.books hasn’t even been populated yet at the time of serialization. Standard AMF serialization would trigger this loading unnecessarily.

Instead, only a list of changes that have occurred to the entity are passed along. This keeps the serialization process light, and quick. Nested properties & collections are handled, and circular references like the one described above are handled efficiently, ensuring that each entity is processed only once.

Essentially, instead of sending through the entire updated entity, dpHibernate sends a collection of changes through to be processed by the server – i.e. :

  • Author record 123 : name changed from “Josh bloch” to “Josh Bloch”
  • Author record 123 : books collection now contains :
    • Book record 123
    • Book record 456
    • A new book record, tentatively identified as ABC
  • Book record 456 : title changed from “effective .net” to “Effective Java”
  • Book record ABC created.

These records are simple objects of primitive types, so serialize very quickly. Once on the server, they are ordered to ensure that dependencies are processed in the appropriate order. Ie, The change record for the creation of Book ABC is processed before it is added to the books collection of Author 123.

Considerations

The entity persistence code of dpHibernate is still new, so typical warnings about bugs apply. That said, dpHibernate is currently being used successfully within a large scale commercial project.

Also, currently these changes to dpHibernate require that your project is using Spring on the Java tier. This dependency will be removed shortly, however for this reason, the entity persistence code is kept separate from the core dpHibernate trunk.

Finally, there are performance implications which you must be careful of. However, these can be easily mitigated through use of new custom metatags, and avoiding state tracking on all entities by default. Fine tuning dpHibernate for performance is discussed in a later blog post.

Advertisements
Tagged

5 thoughts on “Entity Persistence with dpHibernate – Overview

  1. Samildanach says:

    Very interesting post. I have to give a try to dpHibernate. I got a question about the delete operation. In the example you gave about the save you do add and update operations, but if you delete the Book record 123 for example, will it be send to the server ? Does it manage the deletion in the collection of an entity or do I have to do this by hand ?

    • Marty Pitt says:

      Hi. Apologies for the delay in responding!

      The answer is, it depends.

      If you remove book from the collection, then the JPA rules for orphaned entities are followed – ie., deleted if explicity stated to.
      If you simply call book.deleteRecord() then the record is deleted, and the entity is removed from the collection.

      HTH

      Marty

  2. divxer says:

    I’m using dpHibernate 1.4 now, and want to save a entity by call java services. Error is:

    flex.messaging.MessageException: Cannot invoke method ‘loadBean’. Method ‘loadBean’ not found.

    my configuration:

    {“dpHibernate” :
    {
    “serializerFactory” : “net.digitalprimates.persistence.translators.SpringContextSerializerFactory”
    }
    }

    How to solve it? Thanks.

  3. […] persistence https://martypitt.wordpress.com/2010/01/18/entity-persistence-with-dphibernate-overview/ This entry was posted in Uncategorized and tagged dphibernate, Open Source. Bookmark the […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: