I've seen three or four
ORM tool comparisons in the last three weeks; on some weblogs, on our
forum and I've even been part in several decisions.
I have the impression that many developers have problems categorizing and evaluating ORM tools, no matter if its Hibernate, Cayenne, PrIdE (I hope that spelling is correct), or some home-made JDBC framework. I got really frustrated at some point, but what brings me to this blog entry is probably a posting made today, by Scott Ferguson. He compares EJB CMP, JDO, and Hibernate. I wasn't really happy with his list of points. Don't get me wrong, I'm not complaining about Scott's conclusions (our precious Hibernate!), in fact, I actually usually listen to Scott. I've even followed Resins development closely several years ago, nearly got it approved for a medium-sized installation (politics...), and even reported and fixed some bugs.
So, this entry, after a long introduction, is about
comparing ORM solutions. What all the
reviews and articles had in common was a very very obscure criteria schema. In one article,
I've seen someone comparing
loading and saving a single object and looking at the lines of
code that you need for this operation. Next, we hear something like
my ORM should work with
objects or other vague statements that, in practice, probably not help you decide what you should
I did my research for Hibernate in Action, and I think we have found an excellent taxonomy for ORM solutions. Actually, Mark Fussel started to use these categories in 1997, we merely rewrote his list and set it in context to Java application development:
The whole application, including the user interface, is designed around the relational model and SQL-based relational operations. Direct SQL can be fine-tuned in every aspect, but the drawbacks, such as difficult maintenance, lack of portability, and maintainability, are significant, especially in the long run. Applications in this category often make heavy use of stored procedures, shifting some of the work out of the business layer and into the database.
Light object mapping
Entities are represented as classes that are mapped manually to the relational tables. Hand-coded SQL/JDBC is hidden from the business logic using well-known design patterns (such as DAO). This approach is extremely widespread and is successful for applications with a small number of entities, or applications with generic, metadata-driven data models. Stored procedures might have a place in this kind of application.
Medium object mapping
The application is designed around an object model. SQL is generated at build time using a code generation tool, or at runtime by framework code. Associations between objects are supported by the persistence mechanism, and queries may be specified using an object-oriented expression language. Objects are cached by the persistence layer. A great many ORM products and homegrown persistence layers support at least this level of functionality. It's well suited to medium-sized applications with some complex transactions, particularly when portability between different database products is important. These applications usually don't use stored procedures.
Full object mapping
Full object mapping supports sophisticated object modeling: composition, inheritance,
persistence by reachability or a more flexible transitive
persistence solution. The persistence layer implements transparent persistence; persistent
classes do not inherit any special base class or have to implement a special interface. The
persistence layer does not enforce a particular programming model for the domain model
implementation. Efficient fetching strategies (lazy and eager fetching) and caching
strategies are implemented transparently to the application. This level of functionality
can hardly be achieved by a homegrown persistence layer - it's equivalent to months or
years of development time.
In my experience, it is quite easy to find the category for a given product. In Hibernate in Action, we also have a list of interesting questions that you should ask if you compare ORM tools:
- What do persistent classes look like? Are they fine-grained JavaBeans?
- How is mapping metadata defined?
- How should we map class inheritance hierarchies?
- How does the persistence logic interact at runtime with the objects of the business domain?
- What is the lifecycle of a persistent object?
- What facilities are provided for sorting, searching, and aggregating?
- How do we efficiently retrieve data with associations?
In addition, two issues are common to any data-access technology. They also impose fundamental constraints on the design and architecture of an ORM:
- Transactions and concurrency
- Cache management (and concurrency)
Find the answers to those questions, and you can compare ORM software. Scott in fact started right
lifecycle, but he has not given enough information in his article for a real
discussion, it's mostly his opinion (which is fine on a weblog).
There are, as always in life, many solutions and not a single product, project, or specification
will be perfect in all scenarios. You don't have to try to get to the
top of the list and
always use Full object mapping (and the appropriate tool). There are very good reasons to use a
Light object mapping tool (iBatis, for example) in some situations! In many situations, JDBC and
SQL are the best choice. I'm talking about a comparison at the same level, and I've made good
experience with the categories and questions I've shown above. Read the book. :)
Thanks for listening