I finally got a chance to try out upgrading to Hibernate 3 at work. It wasn’t the smoothest of rides, but I got there in the end.
First, some background: the project I’m working on has about 40,000 lines of production code. There are about 100 mapped Hibernate classes. This isn’t small by any means.
The upgrade process went as follows:
- Drop in the new version of Hibernate, and the support files that I needed (antlr, asm, cglib, dom4j, commons-collections and commons-logging). Hunting down which ones I needed to update was painful, but that was more due to the project structure than anything to do with Hibernate.
- Do a quick “search-and-replace” for ‘sf.net.hibernate’ to ‘org.hibernate’. Fixed up a handful of changed packages manually (e.g. net.sf.hibernate.expression to org.hibernate.criterion)
- Changed the cache provider to be the Hibernate-supplied version of EHCache
- Compile, and be amazed at how many times we used the “old” ways of querying and deleting
- Fix all of those. This was fairly mechanical, and I’ll elaborate later.
At this point I had a clean compile, and I was ready to run my unit tests. And that’s when I started hitting issues. So here’s the list:
- There were a lot of classes with private zero-arg constructors, especially on dependant or releated objects. None of these would load in Hibernate 3. The reason, as it turns out, is that classes are now “lazy-loaded” by default in Hibernate 3; that is, the object is used as its own proxy. Previously, the default was no proxy and non-lazy. Lazy loading is good, but it meant that you needed constructors that were at least package-level; private constructors don’t work for some reason. I had about 20 of these, and I couldn’t find an explanation anywhere; eventually, I logged it as a bug, and Gavin King gave me the explanation. Almost invariably, BTW, I want the lazy-load behaviour; I’ll live with package-level zero-arg constructors (though I would prefer private).
- Loading my mapping configuration took ages; creating a configuration and session factory went from ~25 seconds to about 2 minutes. This had me puzzled, but hunting around the Hibernate forum lead me to this post Sure enough, I’d forgotten to update the DTD line in the configuration and mapping file and the delay was caused by repeated resolution of the DTD. This was followed by much self-kicking. Remember to update your mapping files to use the right DTD! (With the right DTD, it took about 16 seconds)
- I had some broken HQL around deletes; it turns out that the Hibernate authors had decided to drop support for aliases in HQLs for delete. So
delete from Foo foo where foo.active = falsedoesn’t work while
delete from Foo where active = falsedoes. Personally, I found this really annoying.
- There’s bugs in the HQL parser around the use of static constants In the Hibernate 3.0 release, java.lang.Character constants aren’t inserted in the HQL correctly. *[Fix will be released in 3.0.2]*
- Deleting entities in one-to-many or many-to-many relationships didn’t work because Hibernate didn’t delete the related rows
- Deleting subclasses didn’t work at all some sort of HQL parser error. *[Fix was released in 3.0.1]*
Due to these issues, I’ve put on hold any further investigation into upgrading Hibernate until they’re resolved. OTH, they do get resolved fast: the HQL with characters constants had a (partial) fix the next day (thanks Gavin).
My recommendation: try it and see. There’s a lot of promise, it’s mostly stable, and the Hibernate folks do push bug fixes out fast. If you hit a problem, report it and get it fixed.
delete(), etc, methods on