Who needs DAOs when there's Hibernate?

I'm sure that everyone is familiar with the data access object or DAO pattern. The basic idea of a DAO is that you encapsulate the nitty gritty details of saving and loading data to and from a persistent store in an object so your application logic isn't riddled with SQL or filesystem access or whatever it is that your DAO does.

In the two years that I've been working with Hibernate, the DAO pattern continues to bother me. I always seem to be writing the same code over and over again: save this, load that, run some query, etc. Whenever I have to repeat myself a lot, I start to think that something's wrong. I eventually put some of the common stuff into a general-purpose DAO class that I used as the superclass for all my other DAOs, but then it seemed that my DAO superclass was just a less-functional wrapper around the Hibernate Session interface. I also kept having to write code to do things that Hibernate already supports, for example, query by example.

A deeper problem, though, is that it's very hard to hide Hibernate behind a DAO. Hibernate is very powerful and exerts an influence on the application even if the Session interface is not visible.

One major difference between Hiberante and an alternative data access strategy such as JDBC is that Hibernate automatically persists changes to objects back to the database when the application--or the container--commits the transaction. JDBC doesn't do that; the application must invoke save methods on the DAO in order to persist changes. So right away, the fact that the DAO is implemented using Hibernate influences the design of the calling code: the callers don't have to explicitly save anything.

Also, objects returned from Hibernate DAOs may be full of lazy-loading proxies that may trigger additional database queries as they are touched by the application. Objects returned from a JDBC DAO definitely don't do that (unless you go to great trouble to implement your own lazy-loading scheme). I realize that the DAO methods could be written to initialize any proxies that were needed by the caller, but now the DAO has to know what the caller wants, and there may need to be multiple versions of the same method, each of which initializes different proxies.

In fact, it's possible to design Hibernate DAOs so that they acted like JDBC DAOs, by initializing proxies and by disconnecting objects from the session before returning them and forcing the application to pass any updated objects to a save method, but what would be the point? You'd have a Hibernate DAO that stripped the application of much of the benefit of using Hibernate in the first place. On the other hand, if you're going to let the application take advantage of Hibernate, then what's the point of hiding Hibernate behind the DAO interfaces? All you're doing is forcing your application to use something less powerful than the Hibernate Session interface and writing a lot of extra code.

Here's my disruptive thought. I think that the Hibernate Session is the ultimate DAO. It does exactly what you'd think a DAO should do: you tell it what objects you need, and it returns them. That's exactly what a JDBC DAO that you might write yourself does. Your application doesn't want to deal with Connections and PreparedStatements and ResultSets, but it does want the business objects, and that's what your JDBC DAO does, convert those ugly JDBC objects into business objects. After you've written a few dozen JDBC DAO objects, you may start thinking that what you really want is one DAO that can give you anything you need, so you don't have to write more JDBC code whenever you add more business objects. That ultimate DAO is the Hibernate Session.

I can think of a couple of other arguments against using Hibernate straight, without DAOs, but I don't think that they are very compelling. Someone will undoubtedly mention that DAOs can be mocked. True, but you can also mock the Session interface. Another argument might be that the DAOs restrict database access patterns to those that have been optimized through the use of indexes or whatever. I suppose whether or not that's a good argument depends on who is going to use your DAOs. If it's yourself, then you can probably trust yourself to use the database properly. If it's another group of people who are not the regular application developers, then I suggest that you probably want to expose some kind of service interface to those folks instead of giving them your DAOs.

I've pretty much convinced myself that wrapping Hibernate in another DAO layer is a waste of effort, but I've not yet put my idea to the test. I'll give it a try over the next few days and write about my experiences.

Comments

Popular posts from this blog

UUIDs as primary keys

Scala and Kotlin

Generating thumbnail images: AffineTransformOp gotchas