Generic DAO example

Para ler a versão em português, clique aqui.

Hey guys!

For this post I’m gonna show how to implement a “Generic DAO” class. It’s something junior developers struggle with, and usually end up writing lots of “DAO” classes doing the exact same thing. A “Generic DAO” is a convenient way to have a single class (or component one might say) responsible for persistent operations in any entity in your code. This is what I mean:

//let's save a Customer entity using it's own DAO class
CustomerDAO customerDAO = new CustomerDAO();
Customer customer = new Customer();
customerDAO.save(customer); //done

//now we would do something similar to other entities
InvoiceDAO invoiceDAO = new InvoiceDAO();
Invoice invoice = new Invoice();
invoiceDAO.save(invoice); //saved

//Why not have a single DAO to both entities?
GenericDAO dao = new GenericDAO();
dao.save(customer);
dao.save(invoice);

Of course that if you’re familiar with JPA/Hibernate you already know (or should) that the persistence manager itself, JPA’s EntityManager or Hibernate’s Session, is already a DAO implementation. For all intent and purposes, a EntityManager/Session object is an abstraction to the persistence layer. For example, the “save” operations shown above could easily be done with the EntityManager alone:

Customer customer = new Costumer();
Invoice invoice = new Invoice();

//EntityManager provide methods for the basic CRUD operations
EntityManager em = getEntityManager(); //returns the EntityManager
em.persist(customer);
em.persist(invoice);

Nonetheless there are still common operations that are not provided out-of-the-box by the EntityManager interface. Some of which I’ll be showing you next:

  • Get all records of a given entity, supplying an order or not.
  • Get all records of a given entity matching a property value.
  • Get all records entity, matching a textual property (using the like operator).

To get a feeling for what I mean, let’s see how the code would look like if we wanted to search for all records of any entity in your domain:

//our "know-it-all" dao
GenericDAO dao = GenericDAO();

//finding all Customers
List<Customer> customers = dao.findAll(Customer.class);

//finding all invoices
List<Invoice> invoices = dao.findAll(Invoice.class);

See? Our GenericDAO class knows how to perform searches on any entity. We can even order our results:

//our "know-it-all" dao
GenericDAO dao = GenericDAO();

//finding all Customers ordering by name
List<Customer> customers = dao.findAll(Customer.class, Order.ASC, "name");

//finding all invoices ordering by value
List<Invoice> invoices = dao.findAll(Invoice.class, Order.DESC, "value");

Nor the EntityManager interface or Hibernate’s Session interface provide this functionally out-of-the-box. And it comes in handy since these sort of operations are done a lot throughout application code.

Here’s how we could implement such a feat using both JPA and pure Hibernate:

//JPA version
public <T extends BaseEntity<?>> List<T> findAll(Class<T> clazz, Order order, String... propertiesOrder) {
    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<T> cq = cb.createQuery(clazz);
    Root<T> root = cq.from(clazz);
		
    List<javax.persistence.criteria.Order> orders = new ArrayList<>();
    for (String propertyOrder : propertiesOrder) {
        if (order.isAscOrder()) {
            orders.add(cb.asc(root.get(propertyOrder)));
        } else {
            orders.add(cb.desc(root.get(propertyOrder)));
        }
    }
    cq.orderBy(orders);

    return entityManager.createQuery(cq).getResultList();
}


//Hibernate version
public <T extends BaseEntity<?>> List<T> findAll(Class<T> clazz, Order order, String... propertiesOrder) {
    Criteria criteria = session.createCriteria(clazz);

    for (String propertyOrder : propertiesOrder) {
        if (order.isAscOrder()) {
            criteria.addOrder(org.hibernate.criterion.Order.asc(propertyOrder));
        } else {
            criteria.addOrder(org.hibernate.criterion.Order.desc(propertyOrder));
        }
    }
    return criteria.list();
}

Both methods do the exact same thing, except that the first is using JPA and the latter just Hibernate. The difference between the two is their criteria API. But in either case, to accomplish this degree of flexibility, finding all records of any entity class, requires the criteria API. There’s a link to download the source code for both implementations at the end of this article. Don’t panic.

Just one more handy example of what a “Generic DAO” can do. Finding entities by their properties:

GenericDAO dao = new GenericDAO();

//find all customers with age 21
List<Customer> customers = dao.findByProperty(Customer.class, "age", 21);

//find all invoices with value 1500.00
List<Invoice> invoices = dao.findByProperty(Invoice.class, "value", 1500.00);

The “age” and “value” Strings supplied above are the name of the properties in each of the entities. (those you always have a get/set method to).

Please keep in mind that having a “generic DAO” in your app is a design choice, not an obligation. Most of the times I do believe that it pays off. It simplifies having to writing code for those same operations over and over again.

As such, most of you might even considerer (I would) having a “generic service” class for this purpose, not just a “generic DAO”. It will make sense in cases where you don’t want your DAOs exposed to your view layer (ManagedBeans and the like).

You can get the source code from github here. Leave a comment below if you have any questions!

Till next time 🙂

5 thoughts on “Generic DAO example

  1. Pingback: Exemplo DAO genérico | Code to live. Live to code.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s