Wednesday, September 12, 2007

The Best Generic Dao Interface Ever

If you Google the phrase "Generic Dao" or "Generified Dao", you'll find several hits all over the internet. They all look like this...

* This sucks, keep reading...
public interface Dao<I extends Serializable, E> {
List<E> loadAll();
E findById(I id);
void save(E entity);
void remove(E entity);

Now, the code above might not even compile, I just slapped it in. The purpose of this interface, and all the examples on the internet, is to define the overall structure of all Daos in the application. This generic Dao interface defines the following contract...
* All Daos will have a loadAll() that returns a list of entity instances.
* All Daos will have a findById method to find an entity with a given "id".
* All Daos will have a save and remove method that takes an entity.

Well isn't this just grand, we now know these four facts about all our Daos. Life is good and we'll all be paid huge for knowing this, right? Not really, the thing with this interface is that you've painted yourself into quite the corner. As your application grows you may not 'need' these methods. Even worse, you might come across cases where you simply shouldn't have these methods. Next thing you know you're trying to split things up into a "ReadOnlyDao" and a "WriteableDao" or some such garbage.

This is the case I found myself in. What did I do on my next project, after learning my lesson?

Try to keep up, this is going to be complex and probably way of the top in the 'voodoo' department. Are you ready?
Ok, here it is...

public interface Dao {

Look out ma! It's a marker interface! You may say, "But Ray, won't chaos ensue? We haven't defined the contrat that all our Daos should follow." Calm down. Do you really think you know how every Entity in your application should be accessed now? I mean if you're writing the "Dao" interface, you're probably pretty early in the project. You really have no idea what all the data access requirements are going to be.

In many systems every Entity has a Repository. Repository is a term gaining popularity over the Dao acronym. Repository is a nice word I guess, but we all call them Daos; so let's just go with it. Each Entity has a Dao. Let the Entity drive the Dao design. Let your domain drive the Dao design. For god's sakes though, don't get on a high horse and try to define it for them with some junk you found on the internet.

Now, the generified version does give you the ability to say that all our methods that destroy Entity instances should be called remove and not destroy on some Daos and delete on others. This rigid construct ends up in place when you may not want a remove method at all. Use something like CheckStyle, or at least have people on your team competent enough to follow the conventions set forth in your project.

Next, we'll talk about "The Best AbstractHibernateDao Ever".


Xanthros said...

I've been using a variation of Christian Bauer/Gavin King's generic dao example.

The main difference I see with yours is that your setting the SessionFactory. I would think this should be the Session.

Any reason why you're using the SessionFactory instead of Session?

Ray Krueger said...

Are you referring to the AbstractHibernateDao's usage of SessionFactory then?

If so, Session is not thread-safe. Sesssions come from the SessionFactory via the "getCurrentSession()" method. Spring manages the creation and closure of sessions for me via the TransactionInterceptor. In any case, the Dao methods should always be asking for the "current session" as a new one may have been created for this thread.

Make sense?

Xanthros said...

The dao version I use either passes in the session or calls getCurrentSession() depending on which constructor you use. And yes I understand session isn't threadsafe. I'm not using Spring however I'm going to look into using DI from Spring or Guice so I can get rid of the lame dao factory I have now.

Anonymous said...

lol - Ray. I did read some of your posts and you make sense, but what's with the "God" complex? You are good but not this good. And btw - interface with just a constructor? I can see what you had in mind, but having an interface like this is pointless (as it does not enforce a contract of any type)

cheers and keep up good work


Ray Krueger said...

The other posts mention my enjoyment of using the 3rd grade article titles in these articles. It's all tongue in cheek fun :)

Non the less, I am that good :)

Anonymous said...

Your arrogance is only surpassed by the inability to grasp the concept. However, since arrogance is, sadly enough, a very easy and profitable way of going through life, you're well on the way. (don't bother answering to this post, this is the first and last time I have visited this this blog)

Ray Krueger said...

You shouldn't go through life taking things so seriously. It's all tongue-in-cheek :)