General J2EE: Rationale of using DAO layer with ORM solution
I feel its not advisable to use DAO layer with an ORM solution.
- Posted by: Nikhil Bajpai
- Posted on: September 02 2005 08:20 EDT
ORM itself is a good enough abstraction over plain JDBC and SQL. An additional DAO layer would only serve to isolate the business layer from the persistence mechanism being used.
Its the nice concept but i feel that the price you pay for this isolation is a bit high:
1. Nearly the same code is duplicated - DAO methods would internally call similar API on ORM
2. Its not clear if the DAO methods would expose the persistant classes themselves or another set of classes.
a) If we decide to hide persistant classes behind DAO layer and expose another set of classes, then for each methos call then for each method call there would be an extra overhead of translation. Insidently, this is the kind of DAO objects that Firestorm generates for Hibernate.
b) If DAO methods expose the persistent objects themselves, then we'd have to worry about weather the business layer works with persistent instances or the transient/detached instances.
In most cases i believe the business layer would work with transient/detached instances. DAO layer would be responsible for making those objects persistent.
In short, the whole scenario starts getting too complicated.
- RE: Rationale of using DAO layer with ORM solution by Nathan Smith on September 02 2005 15:32 EDT
- RE: Rationale of using DAO layer with ORM solution by Emil Kirschner on September 03 2005 09:22 EDT
- Re: RE: Rationale of using DAO layer with ORM solution by Jim Shi on September 07 2006 17:34 EDT
- Rationale of using DAO layer with ORM solution by Nikhil Bajpai on September 05 2005 01:38 EDT
- Rationale of using DAO layer with ORM solution by Jeff Schwartz on July 18 2010 07:20 EDT
The purpose of a DAO layer is that your application not have any notion of what your persistence mechanism is, or even that things are persisted. It's a layer of abstraction that gives you flexibility down the road.
I've relied on this twice in my career. Once was moving a component using Oracle to use a completely different schema (but same object model) in PostgreSQL, and the second was moving from an LDAP directory to an Oracle database (once again, keeping the object model.)
Without the DAO abstraction, these projects would have needed substantial work, with a lot of testing. With the DAO pattern, we just wrote new DAO interface implementations, changed the DAOFactory settings, and the app sitting on top of it just plain worked. We didn't need to test anything other than the queries, because that's all that changed.
If you have a frozen platform and simple ORM using a tool is fulfilling your need, then DAOs might be overkill. But if you ever need to make some major changes, any time spent creating a "redundant" DAO layer will be bought back four or five times.
Oh and as for performance, trust me when I say that having to call a DAO that calls an ORM method is not going to make an appreciable difference in your response time when compared to calling the ORM method directly. If you were that worried about performance, you might optimize the SQL yourself, instead of using a mapping tool.
Nathan is right. The main advantage of the DAO layer is that it completely decouples business logic from persistence technology. This gives you the flexibility required to adapt to your project to constraints dictated by future requirements and economic factors.
For example, you may have to switch from toplink to hibernate because you need to add a few servers to your cluster and keeping toplink - which is priced per processor - would be too expensive. Or your company may choose to drop the in-house RDB based contacts database and go for LDAP. In such cases, trust me, you'd be very happy if all your toplink code would be concentrated in a few DAO classes, cos that's all you'll need change.
The advantages are obvious, I think: a) you don't touch your business logic code, so you don't risk introducing bugs in there. And b) you can easily validate the new DAO layer implementation, because your DAO classes implement interfaces and you already have unit tests for those. So you just keep replacing your toplink code with hibernate until all tests pass.
If your persistence and business logic code is all mixed up in one big bulk then when you'll need to change something in the persistence layer you'll definitely end up changing business logic, and so you'll end up introducing bugs. plus, your persistence code will be spread up all over the place and you'll spend valuable time trying to locate code you need to refactor.
Of course, you can say this will never happen to you. Fact is, in a real life application, on a real market condition, you can never know. You better be prepared.
Emil Kirschner ( http://www.thekirschners.com/ )
I was wondering the same questions for sometime. When you are using Hibernate, I don't feel I need to use another DAO layer. On the contary I would conside it anti-patten. Just wonder how many of developers share my feeling.
Thanks for the replies.
I do understand the importance of DAO. I myself have once benefited by that approach.
But, with ORM tool, that would mean that the DAO layer does not exposes the same set of persistent objects that the ORM layer works on. At least that what i gathered from the code generated by Firestorm/DAO for hibernate.
Even though I don't fully appreciate the pros and cons of exposing the persistent objects through DAO layer, it does not looks good to me due to the following reasons:
1) Persistent objects have to be translated back and forth to the objects exposed by the DAO layer.
2) The fact that ORM layer does not works on the domain objects directly, seems to take a certain edge out of ORM solution. After all, one of the benefits of an ORM solution is that a complicated domain model with all its relationships can be made persistent.
I'd appreciate any inputs on that ?
I do understand the importance of DAO. I myself have once benefited by that approach.But, with ORM tool, that would mean that the DAO layer does not exposes the same set of persistent objects that the ORM layer works on. At least that what i gathered from the code generated by Firestorm/DAO for hibernate.
That's correct. If you wrap your ORM code in a DAO layer it does mean that your business logic is not going to be using the ORM classes directly. In fact, that's really the point. If you wanted to move away from Hibernate in the future to raw JDBC for improved performance, or to EJB 3.0 (or maybe to a new ORM runtime that hasn't been released yet!) then you would be able to do this by simply changing the DAO layer and you would not have to change your business logic.
If the DAO tier simply re-used the Hibernate classes then there would be an immediate tie-in.
FireStorm/DAO actually gives you the choice of using the Hibernate ORM code directly as well as using it wrapped in a DAO layer. Either approach is perfectly acceptable. If you are happy to be tied into Hibernate at this stage in your project then feel free to use the Hibernate ORM classes directly. If you want to be able to swap out Hibernate later on then the DAO approach is a better way to go.
FireStorm/DAO actually gives you the choice of using the Hibernate ORM code directly as well as using it wrapped in a DAO layer.
Thanks Andy. That makes me feel more comfortable.
Actually, we are studying the tools and techniques that help with persistence in Java.
After some initial studies we have come to realize that the approach which directly uses JDBC with embedded SQL is probably the best approach that fits most of the scenarios. Right now we are on the look out of tools that help us implement that strategy. Code generators that can reverse engineer the database schema to generate the data access code are the best choice.
That is the reason we are interested in Firestorm/DAO.
From my first analysis Firestorm looks like a great tools but I can see certain features that can make it more useful:
1. FireStorm does not directly supports many-to-many relationships. For instance suppose “users” table has many to many relationship with “projects” table and “UserProject” is the join table. I expect to see a method (getProjects()) in the user class (generated by reverse mapping) which should return a collection of projects objects for that user. From the classes that are getting generated right now, the only option I have got is to get the collection of UserProject objects and then extract each Project object individually. That would make me fire n+1 queries instead of just one query apart from making it more complicated to use.
2. FireStorm does not have the “unit of work” support. Since firestorm is generating the classes it should be possible for it to have a mechanism for dirty flagging the changed objects. That would enable a manager to intelligently find out the changed objects and persist just those objects when the user sends the signal to end the “unit of work”
3. There is no way to configure FireStorm so that the generated DTO classes extend a custom class. That might help us inject our own “unit of work” mechanism.
4. Each stored procedure gets represented by a separate DAO and a custom DTO object. There is no way to move that method in an existing DAO in order to group data access methods logically.
5. Transaction management is not transparent. User would have to get a connection object and create the DAO object from that connection in order for the DAO objects to participate in the same connection.
6. A separate Manager class (static or singleton) would have helped to provide transparent transactions as well as unit of work.
I might be wrong in my analysis. Please let me know if you feel that some of these shortcomings can be overcome somehow.
Not one of the responses to your article mentioned the fact that when discussing DAO you also have to distinguish between strict layering and non strict layering and that with the onset of ORM DAO has a totally different layering than with raw SQL access providers.
Strict layering requires that DAO and Helpers reside in the infrastructure layer which is one layer below your Business layer where your business objects reside. Strict layering also mandates that no layer can can call methods in layers above it and in addition can only call the api of the layer immdediately below it. Therefore, in the strict layering scenario DAO can only use transparent objects such as maps and lists (etc.) when communicating with your business layer. Returning business objects would violate the strict layering that governs it.
In a relaxed (meaning non strict scenario) the business layer could access the underlying db or have knowledge of it indirectly (for instance, knowing that it is SQL) and pass conditional query criteria to the DAO.
With ORM the rules have changed because the whole purpose of ORM is to persist your business objects. There is no pretext of obfuscating that fact. You feed your business objects to your ORM and your ORM spits out your business objects. The role of DAO when used with ORM therefore is different. In this case your DAO is just an encapsulation of your business rules and which resides between your business object layer and your ORM layer. In fact, most layering schemes place the DAO in their business layer because of this. In this scenario the business object layer and the ORM layer (often the same layer) only communicate to each other via business objects and never need to use transparent objectsl.
It is purely coincidental and unfortunate that the term DAO is used as a general name to describe both use cases. With ORM it really is more of an extension of the business layer while with non ORM architecture it isn't.
So back to your original thesis, the rationale of using DAO layer with ORM solution. Use it if it makes sense to the needs of your sytem. Use it to take advantage of encapsulation of your business rules. Use it to make maintenance easier. Use it to isolate the ORM when there is a posibility of moving to a different one (say from JDO to JPA or Hibernate). In all these cases it makes sense. But don't confuse the different roles that DAO plays in ORM based architecture and non ORM based architecture (such as Groovy's Dataset). You are really talking about 2 different animals here.