adam bien's blog

Generic CRUD Service aka DAO - EJB 3.1/0 Code - Only If You Really Needed 📎

The term Data Access Object (DAO) is actually wrong. An object has state and behavior, and the behavior even can depend on the state. DAO is stateless, only only consists of data manipulation operations. Data Access Procedure (DAP) would be a more exact term. A Data Access Service, or "CRUD Service" would be a better, and even buzzword-compatible, term :-). 

javax.persistence.EntityManager is already a perfect realization of the DAO (DAP) pattern - it is directly injectable into Services (I will cover Services later) or ServiceFacades. Just for CRUD use cases - DAOs are not needed - they would degrade to plain delegates and so dead code. In real projects, however, you will get likely some reusable queries, which should be maintained in a central place. In that case it is absolutely worth to introduce a DAO. If you really need it, you could deploy one DAO-instance, for all use cases. It is easy with generics:

public interface CrudService {
    public  T create(T t);
    public   T find(Class type,Object id);
    public   T update(T t);
    public void delete(Class type,Object id);
    public List findWithNamedQuery(String queryName);
    public List findWithNamedQuery(String queryName,int resultLimit);
    public List findWithNamedQuery(String namedQueryName, Map parameters);
    public List findWithNamedQuery(String namedQueryName, Map parameters,int resultLimit);
}

 The interface-implementation is actually a Service, which always has to be executed behind a ServiceFacade:

@Stateless
@Local(CrudService.class)
@TransactionAttribute(TransactionAttributeType.MANDATORY)
public class CrudServiceBean implements CrudService {
   
    @PersistenceContext
    EntityManager em;
    
    public  T create(T t) {
        this.em.persist(t);
        this.em.flush();
        this.em.refresh(t);
        return t;
    }

    @SuppressWarnings("unchecked")
    public  T find(Class type,Object id) {
       return (T) this.em.find(type, id);
    }

    public void delete(Class type,Object id) {
       Object ref = this.em.getReference(type, id);
       this.em.remove(ref);
    }

    public  T update(T t) {
        return (T)this.em.merge(t);
    }

    public List findWithNamedQuery(String namedQueryName){
        return this.em.createNamedQuery(namedQueryName).getResultList();
    }
    
    public List findWithNamedQuery(String namedQueryName, Map parameters){
        return findWithNamedQuery(namedQueryName, parameters, 0);
    }

    public List findWithNamedQuery(String queryName, int resultLimit) {
        return this.em.createNamedQuery(queryName).
                setMaxResults(resultLimit).
                getResultList();    
    }

    public List findByNativeQuery(String sql, Class type) {
        return this.em.createNativeQuery(sql, type).getResultList();
    }
    
   public List findWithNamedQuery(String namedQueryName, Map parameters,int resultLimit){
        Set> rawParameters = parameters.entrySet();
        Query query = this.em.createNamedQuery(namedQueryName);
        if(resultLimit > 0)
            query.setMaxResults(resultLimit);
        for (Entry entry : rawParameters) {
            query.setParameter(entry.getKey(), entry.getValue());
        }
        return query.getResultList();
    }
}


The only problem are the parameters. The number of parameters is not known in advance, so it has to be passed from the application. I used a simple Builder-Utility, which makes the parameter construction a bit more concise.

public class QueryParameter {
    
    private Map parameters = null;
    
    private QueryParameter(String name,Object value){
        this.parameters = new HashMap();
        this.parameters.put(name, value);
    }
    public static QueryParameter with(String name,Object value){
        return new QueryParameter(name, value);
    }
    public QueryParameter and(String name,Object value){
        this.parameters.put(name, value);
        return this;
    }
    public Map parameters(){
        return this.parameters;
    }
}

 The query-construction is almost fluent:


       int size = this.crudServiceBean.findWithNamedQuery(Book.BY_NAME_AND_PAGES,
                with("name",book.getName()).
                and("pages", book.getNumberOfPages()).
                parameters()).
                size();
        assertEquals(1,size);


I used the implementation above in many Glassfish v2(1) projects, but never in that puristic way. I always added project-specific queries - the actual added value. I wouldn't deploy DAOs just for CRUD, but many architects love it. Its sometimes easier to deploy some superfluous code - just to avoid more expensive discussions :-).

I pushed the origin sample project into http://kenai.com/projects/javaee-patterns - with some unit-tests and two variants. I tested the sample project with Glassfish Prelude v3 and WAR-deployment with Netbeans 6.7m1 - it should work with 6.7rc3 as well.

[The code was originally published in this Real World Java EE Patterns book, Page 141