Wednesday, October 21, 2009

Hibernate Journey

So we have started our new project and by default (not my decision, not saying its a bad decision either, just saying that there could be a better decision) we are going to be using Hibernate.
For those who don't know Hibernate is 'the' ORM solution. ORM is for 'Object Relation Mapping' which is pretty much self explanatory. It maps your relational data model, such as a database schema, to the object model.
The Begining
Back in 2005 we started our project with Hibernate2. There were no annotations yet so we had to use XML files to map the object domain. So here is how the object domain looks like ;
 public class City {
private Long id;
private String name;
... more fields and getter / setters
Our object-domain is made of classes with complex (like other classes or lists...) or primitive (String, Long ...) fields and their getter / setter methods, which is called the 'POJO' (Plain Old Java Object). These POJOs will be representing the rows of a table. String's will be mapped to VARCHAR's on Oracle, complex types will be foreign keys to other tables. Of course we need to specify which POJO is related with which table or which field is mapped to what column. This is done in the mapping XML and here is how it might look like ;
 <class name="foo.City" table="CITY">
<id column="ID" name="id" type="java.lang.Long">
... some mechanism to generate id's
<property column="NAME" name="name" type="java.lang.String"/>
With this model we could save ( 'persist' ) our POJOs to databases with out us explicitly writing insert statements and query our object-domain with a special query language (similar to sql) HQL and get POJOs as result.
The Plugin
We were creating our POJOs through a class modeler (RSAs class diagram plugin) and we realised that we could write a plugin that could also generate the mapping XMLs. All we had to do was mark the class diagrams with some 'StereoType's that we have created;
The things with '<<...>>' are the stereotypes where we could add the table names and such through attributes.
The Evil
I was happily programming until I was told that we were to update to a newer version of Hibernate. Well after the update nothing worked :) . The main reson was that with this version all the relations were 'Lazy' by default (which is the correct way to work with hibernate by the way). To better understand the problem suppose that we are querying the City object. Now we might not be needing the Park's of the City so loading them since it will cause more selects or joins would not be desirable. This is what is trying to be achived with the 'Lazy'. Loading the partial object graph and loading the specific lazy relations only when required.
When we have a City with lazy parks we could load the parks at the time when its getter is called however the city object must have an open session (session is hibernate's transaction unit). If the hibernate session where the city object has been loaded was closed a LazyInitializationException is thrown. Here is a code piece which shows whats ok and whats not :;
City aCity = session.load(City.class,1);
City anotherCity = session.load(City.class,2);
aCity().getParks(); <= OK to call parks here
aCity().getParks(); <= Still OK to call parks here because its already initialized
anotherCity.getParks(); <= This will throw an exception !
The thing to note here is that Hibernate POJOs are not so 'Plain'. A POJO is actually wrapped with hibernate generated proxies to do the initializing when required. You should always think POJOs with the underlying session object. There are numerous patterns to manage the sessions like 'Session Per View', 'Session Per Conversation' pattern ... You should always think of the object graph you will be using and join the objects on your queries according to that.
With the Java 5 came the annotations and it replaced the need to have XMLs. XML is still supported but I don't see any reason why someone choose that to annotations. Here is how our POJO might look like with annotations:
class City {
private Long id;
private String name;
Hibernate has a indexing integration (lucene) , a validation framework and caching frameworks. It should be used with care and respect :)

No comments:

Post a Comment