13

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.

Mercurial
  • 2,095
  • 4
  • 19
  • 33
  • 4
    The same reason why you don't code out your application into one big `main()` method: separation of concerns. (Btw nobody prevents you from coding an abstract `JdbcDaoBase` containing common code and extending that in your `Dao`'s) – rsp Mar 31 '12 at 09:59
  • Why should it be easier to replace 500 methods in 1 class than in 100 classes? – Jens Schauder Feb 01 '14 at 16:09

3 Answers3

22

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.

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
  • Excellent, thank you very much. What about CRUD operations involving multiple tables? Would I, for example, execute a select statement to get an object and use it to call the CRUD of another DAO impl, or maybe create some kind of alien hybrid DAO ? Btw. you've been of great help to me, much appreciated. – Mercurial Mar 31 '12 at 12:00
  • 1
    CRUD or whatever operations involving multiple entities/tables are often handled by Services that aggregate multiple DAOs. In EJB you'll be automatically within the same persistence context even if you call multiple DAOs (it propagates). Another possibility is that if entities are associated (User has-a House), you only need a DAO for a User and JPA will fetch/save/update houses automatically from your User objects. – Arjan Tijms Mar 31 '12 at 12:45
  • 1
    Yeah nice. This approach is one that I followed in various projects. It proved to work quite well and stable. I describe it in detail here: http://codeblock.engio.net/?p=180 – bennidi Feb 01 '14 at 16:08
  • It necessary to override EntityManager in JPAUserDAO instead of using JPABaseDAO? – Akshay Naik Jun 17 '19 at 11:50
1

The whole point of Dependency Injection is to make switching between implementation easier and to decouple the user from the provider. Hence all DI frameworks provide some way to "group" several implementations (here your JDBC-group and your JPA-group) and switch them in one place.

Also: Usually the number of consumers (in your case: some business logic working on users and addresses) is usually higher than the number of DAOs the DI framework will uncouple most of the stuff for you anyway. Assume: 50 business beans, two interfaces and two implementations for each interface (4 total): even basic DI will take care for the 50. Using grouping will halve that remaining rest for you.

Matt
  • 9,068
  • 12
  • 64
  • 84
A.H.
  • 63,967
  • 15
  • 92
  • 126
  • Could you explain the "Also" part, please? Thanks very much. – Mercurial Mar 31 '12 at 12:01
  • "even basic DI will take care for the 50. Using grouping will halve that remaining rest for you." - I fail to understand this. – Mercurial Mar 31 '12 at 12:19
  • @user1304844: Previously I made up a typical example: You have many business beans (e.g. 50). Each business bean usually references several DAOs to delegate the persistence work. In this place DI is the first BIG helper: managing the 50 or more dependencies in one central place - the DI-config. So your intial concern - switching 20 DAO implementations - is much easier using DI, because those 20 changes would be in one place - in the DI config file (versus 50 places as without DI). On top of that (i.e. to make things even more easier) DI frameworks usually provide additional grouping stuff. – A.H. Mar 31 '12 at 12:26
0

There are definitely possibilities to implement the DAO pattern in a widely technology agnostic way such that switching persistence technology or even mixing multiple technologies becomes feasible. This article presents one implementation scheme including source code on github.

http://codeblock.engio.net/?p=180

bennidi
  • 2,092
  • 21
  • 27