Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DAO design pattern

So lets say we have a couple of entities we want to persist using DAO objects. So we implement the right interface so we end up with

class JdbcUserDao implements UserDao{
//...
}

class JdbcAddressDao implements AddressDao{
//...
}

So if I want to be able to switch persistance implementations from JDBC to JPA (for example) and vice versa, I'd need to have JPAUserDao and JPAAddressDao... Meaning if I had 20 entities, and decided to switch implementations(using DI container), I'd have to switch every Jdbc implementation with JPA in code.

Now it could be that I misunderstood how DAO works, but... If I just had

class JdbcDaoImpl implements UserDao,AddressDao{
//...
}

I'd then have all the JDBC implementations in one class, and switching implementations would be a piece of cake. Also, DaoImpl count is equal to number of Dao interfaces. Why not just group them by implementation (jdbc, JTA, JPA...) and have everything under one class?

Thanks in advance.

like image 717
Mercurial Avatar asked Mar 31 '12 09:03

Mercurial


1 Answers

Having a single class implement every DAO interface in your entire application would be a rather bad design.

A more typical pattern is to have a BaseDAO interface (also often called GenericDAO) and have a JPABaseDAO, JDBCBaseDAO etc. These base classes will contain methods like find/get/read, save/store/persist, update/modify and delete/remove/purge.

Specific DAO interfaces like UserDAO then inherit from BaseDAO and concrete implementations like JPAUserDAO extends from JPABaseDAO.

A BaseDAO interface could look like this:

public interface BaseDAO <T> {      
    T getByID(Long ID);
    T save(T type);
    T update(T type);
    void delete(T type);
}

And a UserDAO interface:

public interface UserDAO extends BaseDAO<User> {
    List<User> getAllAuthorized();
}

Bare bones example of a JPABaseDAO implementing this interface:

@Stateless
public class JPABaseDAO<T> implements BaseDAO<T> {

    @PersistenceContext
    private EntityManager entityManager;

    private final Class<T> entityType;

    @SuppressWarnings("unchecked")
    public JPABaseDAO() {
        this.entityType = ((Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
    }

    @Override
    public T getByID(Long ID) {
        return entityManager.find(entityType, ID);
    }

    @Override  
    public T save(T type) {
        return entityManager.persist(type);        
    }

    @Override  
    public T update(T type) {        
        return entityManager.merge(type);
    }

    @Override
    public void delete(T type) {
        entityManager.remove(entityManager.contains(type) ? type : entityManager.merge(type));
    }

}

And some sample UserDAO implementation that would inherit from it:

@Stateless
public class JPAUserDAO extends JPABaseDAO<User> implements UserDAO {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public List<User> getAllAuthorized() {
        return entityManager.createNamedQuery("User.getAllAuthorized", User.class)
                            .getResultList();
    }
}

In practice the base class can often do some other things transparently, for instance checking if an entity implements some kind of Auditable interface, and automatically setting the date and user that modified it, etc.

When using EJB to implement your DAOs, one strategy to change implementations would be to put all JDBC implementations in one package and all JPA implementations in the other. Then just include only one implementation package in your build.

like image 63
Arjan Tijms Avatar answered Oct 23 '22 07:10

Arjan Tijms