Cayenne and Hibernate

Try downloading a copy and start testing the Hibernate mappings with DBUnit.

Anyway a few days ago The Server Side (TSS) posted an article (discussion thread here) about a new (to me that is) ORM mapping tool called Cayenne. I was intrigued so I downloaded a copy and started making the following object graph persistable (I also blogged about my expierence testing the Hibernate mappings with DBUnit here a couple of weeks ago.).

Class Model

At any rate as I mentioned in the other blog entry I already had this graph persisted in Hibernate and was really happy with the useability and performance. But like one of my kids in the lego store I could not resist touching something that proported to be 'like' EOF. So I downloaded it and made the Stock Tracker model persistent with Cayenne too.

This entry will highlight the differences I noticed in the programming models between the two and the pluses and minuses to Cayenne as I experienced them while goiing through this exercise.

First off I loved the modeling tool. I'm a sucker for tools like this. I know I should be into hacking XML but as was noted in another thread XML is only for advanced developer. I'm not one (tounge firmly in cheek for those without a sense of humor).

The tool worked great and once I got my head wrapped around how to use it I really liked it. Generally I found the operations (make a relationship,etc) intuitive and where I expected them to be

The Cayenne API is about as easy to use as the Hibernate API

For example here is the code to create 100 simple SiteUser objects and save them to the DB with Cayenne

public void testInsertLotsOfUsers() throws Exception {
long start = System.currentTimeMillis();
for (int i = 0; i < 100; i++) {
SiteUser user = (SiteUser)context.createAndRegisterNewObject(SiteUserCayenne.class);
user.setUname("insert-test" + i);
System.err.println("cayenne save & flush done = " + (System.currentTimeMillis() - start));

Here is the same functionality done with Hibernate

public void testInsertLotsOfUsers() throws Exception {
long start = System.currentTimeMillis();
for (int i = 0; i < 100; i++) {
SiteUserHibernate user = new SiteUserHibernate();
user.setUname("insert-test" + i);
System.err.println("hibernate save & flush done = " + (System.currentTimeMillis() - start));

In Cayenne you ask the DataContext to create a new object for you, which registers the object and assigns it a temporary identifier and makes Cayenne keep track of it. In Hibernate you create the object just like any other POJO and 'register' it with Hibernate with the save(Object) method. With Cayenne you call commitChanges() and you are done. With Hibernate you call flush().

The performance of the two frameworks is roughly the same. For this very simple use (inserting 100 simple objects) the two frameworks were almost identical. Hibernate averaged (over 5 runs) 413 milliseconds and Cayenne averaged 410 milliseconds.

The usage of the two systems are very close but varry slightly. Here are a few of the differences I noticed in my simple hiearchy.

  • In Hibernate you can specify the means of building a primary key - In Cayenne its taken care of automatically for you and you don't have think about it if you don't want to.
  • In Hibernate the persistence is purely orthogonal to the objects and you can persist any POJO that you can map - In Cayenne the objects that are persisted know they are persistent
  • In Hibernate I ususally use XDoclet to define my Hibernate mappings in my Java classes and never think about them - In Cayenne you must use the modeling tool to define the mappings as far as I could tell (i.e. there are no XDoclet tags to generate Cayenne mappings).
  • As a result of the XDoclet tags the java code becomes the single source of business logic as well as persistence mapping info - In Cayenne the tool is the single source of mapping information and your Java code is the single source of the business logic

In Cayenne when you generate Java code from the modeling tool two classes are generated that have an inheritance relationship for each entity defined in the model. The super class is responsible for the 'persistence' behavior and the subclass is responsible for the 'business logic'. Each time the code is regenerated the superclass is rebuilt but the subclass is left alone.

Cayenne's abstract super class for persistent objets also has a 'meta' feel too it. For example you can tell any persistent object to writeProperty(String propertyName, Object value). This is very much like EOF worked with Obj-C, except since Obj-C was an untyped dynamic language all the code for 'writeProperty' was implemented in terms of runtime API calls instead of through a hash table.

Overall in my limited expierence Cayenne is a robust and fun framework to develop with. There are lots of cool features and if you know Hibernate its a small leap to grok Cayenne. Cayenne seems to have a vibrant community of users and the list was very friendly and answered my simpleton questions quickly and without trying to make me feel stupid. Cayenne seems to be a bit less mature than Hibernate in a few areas, for example, the distributed caching is new in version 1.1. In general though Cayenne is a great framework and I would definitely recommend that you take a look at it when you start your next project that requires an ORM framework.

About the author

Author: Bill Dudney Blog: Bill Dudney is, in addition to an author and frequent speaker, a senior J2EE architect consultant. He has been doing distributed computing for 14 years starting at NASA, building software to manage the mass properties of the Space Shuttle. Bill started doing Java in late 1996 after years of building software on the NeXT. Bill is the author of three books; J2EE AntiPatterns, Jakarta Pitfalls and Mastering JavaServer Faces. Bill travels on the No Fluff Just Stuff symposium tour as an expert speaker on many J2EE topics.

Dig Deeper on Web application framework and Java middleware

Start the conversation

Send me notifications when other members comment.

Please create a username to comment.