Hibernate: CRUD Generic DAO

59,427

Solution 1

here's mine

@Component
public class Dao{

    @Resource(name = "sessionFactory")
    private SessionFactory sessionFactory;

    public <T> T save(final T o){
      return (T) sessionFactory.getCurrentSession().save(o);
    }


    public void delete(final Object object){
      sessionFactory.getCurrentSession().delete(object);
    }

    /***/
    public <T> T get(final Class<T> type, final Long id){
      return (T) sessionFactory.getCurrentSession().get(type, id);
    }

    /***/
    public <T> T merge(final T o)   {
      return (T) sessionFactory.getCurrentSession().merge(o);
    }

    /***/
    public <T> void saveOrUpdate(final T o){
      sessionFactory.getCurrentSession().saveOrUpdate(o);
    }

    public <T> List<T> getAll(final Class<T> type) {
      final Session session = sessionFactory.getCurrentSession();
      final Criteria crit = session.createCriteria(type);
  return crit.list();
    }
// and so on, you shoudl get the idea

and you can then access like so in service layer:

 @Autowired
    private Dao dao;

   @Transactional(readOnly = true)
    public List<MyEntity> getAll() {
      return dao.getAll(MyEntity.class);
    }

Solution 2

Spring Data JPA is a wonderful project that generate DAOs for you, and more! You only have to create an interface (without any implementation):

interface PaymentMethodsDao extends JpaRepository<PaymentMethods, Integer> {}

This interface (via inherited JpaRepository) will automatically give you:

PaymentMethod save(PaymentMethod entity);
Iterable<PaymentMethod> save(Iterable<? extends PaymentMethod> entities);
PaymentMethod findOne(Integer id);
boolean exists(Integer id);
Iterable<PaymentMethod> findAll();
long count();
void delete(Integer id);
void delete(PaymentMethod entity);
void delete(Iterable<? extends PaymentMethod> entities);
void deleteAll();
Iterable<PaymentMethod> findAll(Sort sort);
Page<PaymentMethod> findAll(Pageable pageable);
List<PaymentMethod> findAll();
List<PaymentMethod> findAll(Sort sort);
List<PaymentMethod> save(Iterable<? extends PaymentMethods> entities);
void flush();
PaymentMethod saveAndFlush(PaymentMethods entity);
void deleteInBatch(Iterable<PaymentMethods> entities);

The interface is strongly typed (generics) and automatically implemented for you. For every entity all you have to do is to create an interface extending JpaRepository<T,Integer extends Serializable>.

But wait, there's more! Assuming your PaymentMethod has name and validSince persistent fields. If you add the following method to your interface:

interface PaymentMethodsDao extends JpaRepository<PaymentMethods, Integer> {

  Page<PaymentMethod> findByNameLikeAndValidSinceGreaterThan(
    String name, Date validSince, Pageable page
  );

}

the framework will parse the method name:

findBy (Name like) And (ValidSince greater than)

create the JPA QL query, apply paging and sorting (Pageable page) and run it for you. No implementation needed:

paymentMethodsDao.findByNameLikeAndValidSinceGreaterThan(
  "abc%",
  new Date(),
  new PageRequest(0, 20, Sort.Direction.DESC, "name"
);

Resulting query:

SELECT *  //or COUNT, framework also returns the total number of records
FROM PaymentMethods
WHERE name LIKE "abc%"
  AND validSince > ...

And with paging applied.

The only downside is that the project is rather new and it is relatively easy to hit buts (but it is very actively developed).

Solution 3

Do not write specific dao for each entity. You can implement one generic DAO that does 90% of work for all entities you need. You can extend it in cases you want specific treatment of certain entities.

In project I am currently working on we have such DAO that wraps Hibernate session providing methods similar to those that you described. Moreover we are using ISearch API - the open source project hosted at google code and providing very convenient criteria building interface for Hibernate and JPA.

Solution 4

you can use Generic DAO as leverage for other Domain specific DAO classes. Suppose you have an Employee Domain class as:

  @Entity
  @Table(name="employee")
  public class Employee {

    @Id
    @Column(name="id")
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;

    @Column(name="emp_name")
    private String empName;

    @Column(name="emp_designation")
    private String empDesignation;

    @Column(name="emp_salary")
    private Float empSalary;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public String getEmpDesignation() {
        return empDesignation;
    }

    public void setEmpDesignation(String empDesignation) {
        this.empDesignation = empDesignation;
    }

    public Float getEmpSalary() {
        return empSalary;
    }

    public void setEmpSalary(Float empSalary) {
        this.empSalary = empSalary;
    }


}

then the required generic DAO would look something like this:

Generic DAO Interface:

 public interface GenericRepositoryInterface<T> {

    public T save(T emp);
    public Boolean delete(T emp);
    public T edit(T emp);
    public T find(Long empId);
}

Generic DAO implementation:

@Repository
public class GenericRepositoryImplementation<T> implements GenericRepositoryInterface<T> {

protected EntityManager entityManager;
private Class<T> type;

public GenericRepositoryImplementation() {
    // TODO Auto-generated constructor stub

}

public GenericRepositoryImplementation(Class<T> type) {
    // TODO Auto-generated constructor stub

    this.type = type;
}

public EntityManager getEntityManager() {
    return entityManager;
}

@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
    this.entityManager = entityManager;
}
@Override
public T save(T emp) {
    // TODO Auto-generated method stub
    entityManager.persist(emp);
    entityManager.flush();
    return emp;
}

@Override
public Boolean delete(T emp) {
    // TODO Auto-generated method stub
    try {
         entityManager.remove(emp);
    } catch (Exception ex) {
        return false;
    }
    return true;
}

@Override
public T edit(T emp) {
    // TODO Auto-generated method stub
    try{
       return entityManager.merge(emp);
    } catch(Exception ex) {
        return null;
    }
}

@Override
public T find(Long empId) {
    // TODO Auto-generated method stub
    return (T) entityManager.find(Employee.class, empId);
}
} 

This generic DAO class then needs to be extended by every Domain specific DAO class. The Domain specific DAO class may even implement another interface for operations that are not common in general. And prefer sending type information using constructor.

Solution 5

you can create a baseDAO Interface and a baseDAO implementation class. And When you need specific use case with different class types you can just create that class's DAO which inherit baseDAO class and implement extra interface with that class's specific needs like this

IBaseDAO

 public interface IBaseDAO<T> {

/**
 * @Purpose :Save object of type T
 * @param transientInstance
 */
public Object persist(final T transientInstance);

/**
 * @Purpose :Delete object of type T
 * @param persistentInstance
 */
public void remove(final T persistentInstance);

/**
 * @Purpose :Update Object of type T
 * @param detachedInstance
 * @return
 */
public T merge(final T detachedInstance);

/**
 * @Purpose :Find object by 'id' of type T
 * @param identifier
 * @return
 */
public T findById(final Long identifier, Class<?> persistClass);
}

BaseDAO Class

public class BaseDAO<T> implements IBaseDAO<T> {

@Autowired
private SessionFactory sessionFactory;

public Object persist(T entity) {
    return this.getSession().save(entity);
}

@Override
public void remove(T persistentInstance) {
    this.getSession().delete(persistentInstance);
}

@SuppressWarnings("unchecked")
@Override
public T merge(T detachedInstance) {
    return (T) this.getSession().merge(detachedInstance);
}

@SuppressWarnings("unchecked")
@Override
public T findById(Long identifier, Class<?> persistClass) {
    return (T) this.getSession().get(persistClass, identifier);
}

public SessionFactory getSessionFactory() {
    return sessionFactory;
}

public Session getSession() {
    return getSessionFactory().getCurrentSession();
}

}

and specific interface

public interface IUserDAO extends IBaseDAO<User> {

   public User getUserById(long userId);

   public User findUserByUsername(String username);

}

and classes like this

@Repository("userDAO")
public class UserDAO extends BaseDAO<User> implements IUserDAO {

public User getUserById(long userId) {
    return findById(userId, User.class);
}

@Override
    public User findUserByUsername(String username) {
        Criteria criteria = getSession().createCriteria(User.class);
        criteria.add(Restrictions.eq("username", username));
        return (User) criteria.uniqueResult();
    }

}
Share:
59,427
Fabio B.
Author by

Fabio B.

http://www.linkedin.com/in/fabiobozzo

Updated on July 13, 2020

Comments

  • Fabio B.
    Fabio B. almost 4 years

    My web application has got a lot of service tables/entities, such as payment_methods, tax_codes, province_codes, etc.

    Each time I add a new entity, I have to write a DAO. The thing is that, basically, they are all the same, but the only difference is the entity class itself.

    I know that Hibernate tools can generate the code for me automatically but I can't use them now (don't ask why) so I'm thinking of a Generic DAO. There's a lot of literature about that but I can't put pieces together and make it work with Spring.

    It's all about generics I think, it will have four basic methods:

    • listAll
    • saveOrUpdate
    • deleteById
    • getById

    and that's all.


    Question:

    What's the best practice for not re-inventing the wheel? Isn't there something ready to use, yet?

  • Fabio B.
    Fabio B. about 12 years
    1) can you edit your answer with the spring xml bean configuration for a real world dao?
  • Mario David
    Mario David over 11 years
    hi, can you show a snippet, where you use the PaymentMethodsDao Implementation? i can't figure out how to get a running example how to use this interface... thx!
  • Tomasz Nurkiewicz
    Tomasz Nurkiewicz over 11 years
    @MarioDavid: you just inject PaymentMethodsDao to your other beans and use it. Spring will implement it for you.
  • Edward Kennedy
    Edward Kennedy over 8 years
    Why not use the first example and then inherit from it?
  • Shahid Yousuf
    Shahid Yousuf over 8 years
    If i got it correct, you mean to say inheriting GenericRepositoryImplementation. That is what is to be done. Now the Employee specific DAO has to inherit from GenericRepositoryImplementation class for common methods apart from implementing its own Interface.
  • Woland
    Woland over 6 years
    @NimChimpsky Why did you use SessionFactory instead of EntityManager? Which approach is better?
  • Jumi
    Jumi over 6 years
    What if not all my tables have longs as id?
  • NimChimpsky
    NimChimpsky over 6 years
    @Jumi they probably should have
  • Jumi
    Jumi over 6 years
    @NimChimpsky Yeah, i went that way. But i like the idea of generic repositories more. Like this: public class UserRepository extends AbstractRepository<User,Long>. I couldn't find a sollution for this though that works in a weblogic container. That said i'm coming from php symfony and only getting to know java and java ee. Maybe the symfony conventions makes me think it's better way.