Generic DAO with Custom Method

db-chain1
Instead of having DAO for each entity, calling Generic DAO simplify the program.
Unlike the template classes with empty method that can only use the method specified in Generic DAO classes, this example use additional customized method (Source Code)

2015-05-30_11h15_25

2015-05-30_11h17_10

package com.ns.spring.dao.template;

import java.util.List;

import com.ns.spring.dao.GenHbDao;
import com.ns.spring.model.RMA_LINE;

public interface RmaLineDao extends GenHbDao<RMA_LINE, String> {

	public List<Object[]> getListRmaLineBySql(String rmaNum, String rmaLineNum);
	public RMA_LINE getRmaLineByHql(String rmaNum, String rmaLineNum);
}
package com.ns.spring.dao.template.impl;
package com.ns.spring.dao.template.impl;

import java.util.List;

import org.hibernate.Query;
import org.springframework.stereotype.Repository;

import com.ns.spring.dao.GenHbDaoImpl;
import com.ns.spring.dao.template.RmaLineDao;
import com.ns.spring.model.RMA_LINE;

@Repository
public class RmaLineDaoImpl extends GenHbDaoImpl<RMA_LINE, String> implements RmaLineDao {

	@SuppressWarnings("unchecked")
	@Override
	public List<Object[]> getListRmaLineBySql(String rmaNum, String rmaLineNum) {
		
		StringBuilder sb = new StringBuilder();
		sb.append("\n");
		sb.append("SELECT\n");
		sb.append("  rl.rma_num\n");
		sb.append(" ,rl.rma_line_num\n");
		sb.append(" ,rl.rma_line_sts_cd\n");
		sb.append(" ,sts.rma_hdr_sts_nm\n");
		sb.append(" ,rl.mdse_cd\n");
		sb.append(" ,mdse.mdse_nm\n");
		sb.append(" ,rl.qty\n");
		sb.append(" ,rl.rma_id\n");
		sb.append("FROM RMA_LINE rl\n");
		sb.append("LEFT OUTER JOIN RMA_HDR_STS sts\n");
		sb.append("ON rl.rma_line_sts_cd = sts.rma_hdr_sts_cd\n");
		sb.append("LEFT OUTER JOIN MDSE mdse\n");
		sb.append("ON rl.mdse_cd = mdse.mdse_cd\n");
		sb.append("WHERE rl.rma_num = :rmaNum\n");
		if (rmaLineNum != null) {
			sb.append("AND rl.rma_line_num = :rmaLineNum\n");
		}		
		sb.append("ORDER BY\n");
		sb.append("  rl.rma_num\n");
		sb.append(" ,rl.rma_line_num\n");

		Query query = super.getCurrSession().createSQLQuery(sb.toString());
		query.setParameter("rmaNum", rmaNum);
		if (rmaLineNum != null) {
			query.setParameter("rmaLineNum", rmaLineNum);
		}
		List<Object[]> list = query.list();
		return list;
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public RMA_LINE getRmaLineByHql(String rmaNum, String rmaLineNum) {

		String hqlStr = "from RMA_LINE " 
				+ "where rma_num = :rmaNum "
				+ "and   rma_line_num = :rmaLineNum ";
		
		Query query = super.getCurrSession().createQuery(hqlStr);
		query.setParameter("rmaNum", rmaNum);
		query.setParameter("rmaLineNum", rmaLineNum);

		List<RMA_LINE> list = query.list();
		if (list != null && list.size() > 0) {
			return (RMA_LINE) list.get(0);
		}
		return null;
	}
}

DAO interface, and it’s implementation has two additional methods:
1. Native SQL with its reesult
2. HQL with its reesult

package com.ns.spring.service.template;

import java.util.List;

import com.ns.spring.model.RMA_LINE;
import com.ns.spring.service.GenHbService;

public interface RmaLineService extends GenHbService<RMA_LINE, String> {

	public List<Object[]> getListRmaLineBySql(String rmaNum, String rmaLineNum);
	public RMA_LINE getRmaLineByHql(String rmaNum, String rmaLineNum);
}
package com.ns.spring.service.template.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ns.spring.dao.GenHbDao;
import com.ns.spring.dao.template.RmaLineDao;
import com.ns.spring.model.RMA_LINE;
import com.ns.spring.service.GenHbServiceImpl;
import com.ns.spring.service.template.RmaLineService;

@Service("rmaLineService")
public class RmaLineServiceImpl extends GenHbServiceImpl<RMA_LINE, String> implements RmaLineService {

	private RmaLineDao dao;

	public RmaLineServiceImpl() {
	}

	@Autowired
	public RmaLineServiceImpl(@Qualifier("rmaLineDaoImpl") GenHbDao<RMA_LINE, String> genericDao) {
		super(genericDao);
		this.dao = (RmaLineDao) genericDao;
	}
	
	@Override
	@Transactional
	public List<Object[]> getListRmaLineBySql(String rmaNum, String rmaLineNum) {
		return this.dao.getListRmaLineBySql(rmaNum, rmaLineNum);
	}

	@Override
	@Transactional
	public RMA_LINE getRmaLineByHql(String rmaNum, String rmaLineNum) {
		return this.dao.getRmaLineByHql(rmaNum, rmaLineNum);
	}
}

DAO service interface, and it’s implementation calling super class, and two custom method defined in RmaLineDaoImpl.

Generic DAO without Custom Method

db-chain1
Instead of having DAO for each entity, calling Generic DAO simplify the program. (Source Code)

2015-05-30_09h48_00

2015-05-30_09h53_38

package com.ns.spring.dao.template;

import com.ns.spring.dao.GenHbDao;
import com.ns.spring.model.MDSE;

public interface MdseDao extends GenHbDao<MDSE, String> {

}
package com.ns.spring.dao.template.impl;

import org.springframework.stereotype.Repository;

import com.ns.spring.dao.GenHbDaoImpl;
import com.ns.spring.dao.template.MdseDao;
import com.ns.spring.model.MDSE;

@Repository
public class MdseDaoImpl extends GenHbDaoImpl<MDSE, String> implements MdseDao {

}

Empty DAO interface, and it’s implementation

package com.ns.spring.service.template;

import com.ns.spring.model.MDSE;
import com.ns.spring.service.GenHbService;

public interface MdseService extends GenHbService<MDSE, String> {

}

package com.ns.spring.service.template.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import com.ns.spring.dao.GenHbDao;
import com.ns.spring.dao.template.MdseDao;
import com.ns.spring.model.MDSE;
import com.ns.spring.service.GenHbServiceImpl;
import com.ns.spring.service.template.MdseService;

@Service("mdseService")
public class MdseServiceImpl extends GenHbServiceImpl<MDSE, String> implements MdseService {

	private MdseDao dao;

	public MdseServiceImpl() {
	}

	@Autowired
	public MdseServiceImpl(@Qualifier("mdseDaoImpl") GenHbDao<MDSE, String> genericDao) {
		super(genericDao);
		this.dao = (MdseDao) genericDao;
	}
}

Empty DAO service interface, and it’s implementation calling super class. It can use the method defined in Generic DAO

Generic DAO

db-chain1
For the CRUD operation in Hibernate, you don’t need to repeat Insert, Update, Delete at all. The Generic DAO can take any entity object to do this.

It can be accessed by any entity object with empty method, or some additional customize method

There are Service, and DAO layer, and your controller access Service class
Controller <-> Service <-> DAO : Source Code
model2

The interface of Generic DAO.

package com.ns.spring.dao;

import java.io.Serializable;
import java.util.List;

import com.ns.spring.exception.NSException;

public interface GenHbDao<E, K extends Serializable> {

	public List<E> findAll();	
	public E findById(K key) throws NSException;
	public void save(E obj);
	public void update(E obj);
	public void saveOrUpdate(E obj);
	public void delete(E obj);

}

The implementation of above interface

package com.ns.spring.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

import org.hibernate.ObjectNotFoundException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.ns.spring.exception.NSException;

@SuppressWarnings("unchecked")
@Repository
public abstract class GenHbDaoImpl<E, K extends Serializable> implements GenHbDao<E, K> {

	private SessionFactory sessionFactory;
	private Class<E> clazz;

	public GenHbDaoImpl() {
		Type t = getClass().getGenericSuperclass();
		ParameterizedType pt = (ParameterizedType) t;
		this.clazz = (Class<E>) pt.getActualTypeArguments()[0];
	}

	public Class<E> getCurrClazz() {
		return clazz;
	}

	@Autowired
	public void setSessionFactory(SessionFactory sf) {
		this.sessionFactory = sf;
	}

	protected Session getCurrSession() {
		return sessionFactory.getCurrentSession();
	}

	@Override
	public void save(E obj) {
		this.getCurrSession().persist(obj);
	}

	@Override
	public void update(E obj) {
		this.getCurrSession().update(obj);
	}

	@Override
	public void saveOrUpdate(E obj) {
		this.getCurrSession().saveOrUpdate(obj);
	}

	@Override
	public void delete(E obj) {
		this.getCurrSession().delete(obj);
	}

	@Override
	public List<E> findAll() {
		List<E> list = this.getCurrSession().createCriteria(getCurrClazz()).list();
		return list;
	}

	@Override
	public E findById(K key) throws NSException {
		Session session = this.getCurrSession();
		try {
			E p = (E) session.load(getCurrClazz(), key);
			return p;
		} catch (ObjectNotFoundException e) {
			throw new NSException("No result");
		}
	}
}

The interface of Service class (nearly identical of Generic DAO) that actually called by your controller.

package com.ns.spring.service;

import java.io.Serializable;
import java.util.List;

public interface GenHbService<E, K extends Serializable> {

	public List<E> findAll();
	public E findById(K key);
	public void save(E obj);
	public void update(E obj);
	public void saveOrUpdate(E obj);
	public void delete(E obj);

}

And finally the implementation of the above service interface. Notice the @Transactional annotation in each method

package com.ns.spring.service;

import java.io.Serializable;
import java.util.List;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.ns.spring.dao.GenHbDao;
import com.ns.spring.exception.NSException;

@Service
public abstract class GenHbServiceImpl<E, K extends Serializable> implements GenHbService<E, K> {

	private GenHbDao<E, K> genDao;

	public GenHbServiceImpl(GenHbDao<E, K> genDao) {
		this.genDao = genDao;
	}

	public GenHbServiceImpl() {
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED)
	public void save(E obj) {
		genDao.save(obj);
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED)
	public void update(E obj) {
		genDao.update(obj);
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED)
	public void saveOrUpdate(E obj) {
		genDao.saveOrUpdate(obj);
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED)
	public void delete(E obj) {
		genDao.delete(obj);
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED)
	public List<E> findAll() {
		return genDao.findAll();
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED)
	public E findById(K key) {
		try {
			return genDao.findById(key);
		} catch (NSException e) {
			return null;
		}
	}
}