49

Following my previous question, DAO and Service layers (JPA/Hibernate + Spring), I decided to use just a single DAO for my data layer (at least at the beginning) in an application using JPA/Hibernate, Spring and Wicket. The use of generic CRUD methods was proposed, but I'm not very sure how to implement this using JPA. Could you please give me an example or share a link regarding this?

Community
  • 1
  • 1
John Manak
  • 13,328
  • 29
  • 78
  • 119

5 Answers5

91

Here is an example interface:

public interface GenericDao<T, PK extends Serializable> {
    T create(T t);
    T read(PK id);
    T update(T t);
    void delete(T t);
}

And an implementation:

public class GenericDaoJpaImpl<T, PK extends Serializable> 
    implements GenericDao<T, PK> {

    protected Class<T> entityClass;

    @PersistenceContext
    protected EntityManager entityManager;

    public GenericDaoJpaImpl() {
        ParameterizedType genericSuperclass = (ParameterizedType) getClass()
             .getGenericSuperclass();
        this.entityClass = (Class<T>) genericSuperclass
             .getActualTypeArguments()[0];
    }

    @Override
    public T create(T t) {
        this.entityManager.persist(t);
        return t;
    }

    @Override
    public T read(PK id) {
        return this.entityManager.find(entityClass, id);
    }

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

    @Override
    public void delete(T t) {
        t = this.entityManager.merge(t);
        this.entityManager.remove(t);
    }
}
Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
  • 2
    How would this fit in with slsb's and pojo entities (representing the db tables) ? – NimChimpsky Oct 08 '10 at 11:20
  • 3
    Great answer. Just a few comments: I rather pass the Class as a parameter in the constructor method (instead of a unchecked cast); the parameter t in the delete method should not be reassigned and the class would preferably be abstract. – megathor Jul 16 '14 at 01:58
  • 1
    I tried to follow this example but the `ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();` code is throwing `java.lang.ClassCastException` with the following message: `java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType` Do anybody know how to fix this? Thanks anyway. – Loa Jul 28 '16 at 21:22
  • Why there is no transactions? I mean `entityManager.getTransaction().begin();` and `entityManager.getTransaction().commit();`. – Woland Sep 13 '17 at 16:05
  • 1
    @Woland If using JTA you do not need to all those methods, in fact IIRC it will throw an exception if you try to call those methods in a JTA context. – Neilos Nov 03 '17 at 22:02
15

Based on the article Don't repeat the DAO we used this kind of technique for many years. We always struggled with problems with our patterns after we realized that we made a big mistake.

By using an ORM tool such as Hibernate or JPA you will not have to think DAO and Service layer separately. You can use EntityManager from your service classes as you know the lifecycle of transactions and the logic of your entity classes there.

Do you save any minute if you call myDao.saveEntity instead of simply entityManager.saveEntity? No. You will have an unnecessary dao class that does nothing else but will be a wrapper around EntityManager. Do not afraid to write selects in your service classes with the help of EntityManager (or session in hibernate).

One more note: You should define the borders of your service layer and do not let programmers to return or wait for Entity classes. The UI or WS layer programmers should not know at all about entity classes only about DTO-s. Entity objects have lifecycles that most of the programmers do not know about. You will have really serious issues if you store an entity object in a session data and try to update it back to the database seconds or hours later. Well you may would not do it but a programmer of the UI who knows the parameter types and return types of your service layer only would do to save some lines of code.

Sam R.
  • 16,027
  • 12
  • 69
  • 122
Balazs Zsoldos
  • 6,036
  • 2
  • 23
  • 31
  • Annotated transaction management in EJB?! Though you probably need much more sophisticated DAO, which will not be generic anymore, but anyways. I still find this method can be useful in specific cases. – Ville Myrskyneva Feb 05 '15 at 07:34
5

I was looking for this same thing. I found what appears to be exactly that- the Spring-Data JPA project provided by SpringSource. This is a code port from Hades and has now (Early 2011) been swallowed by Spring and better integrated. It allows you to use a single dao (SimpleJpaRepository) with a static create, or extend the base JpaRepository class to create any object specific dao with ready made CRUD+ methods. Also allows grails like queries just by using params names as the name of the method- in the interface (no implementation required!) i.e. findByLastname(String lastName); Looks very promising- being part of Spring projects will certainly ensure some future for it too. I have begun implementing this in my upcoming project now.

Danny C
  • 2,980
  • 2
  • 28
  • 20
2

if you are looking for a third party implementation , you can check http://www.altuure.com/projects/yagdao/ . it is a nnotation based generic DAO framework which supports JPA and hibernate

altuure
  • 193
  • 2
  • 9
1

You may also have a look at http://codeblock.engio.net/data-persistence-and-the-dao-pattern/

The related code can be found on github https://github.com/bennidi/daoism

It has integration with Spring and configuration examples for Hibernate and EclipseLink

bennidi
  • 2,092
  • 21
  • 27