Introducción a DAO

Cuando se trabaja con una base de datos a través de JDBC o incluso a través de Hibernate, muchas veces el código resulta más engorroso de lo que nos gustaría. Una consulta de base de datos a menudo contiene:

  • validación de datos
  • configuración de parámetros de solicitud
  • Selección de consulta HQL en función de los parámetros de consulta
  • construir una consulta usando la API de criterios
  • configuración de almacenamiento en caché
  • manejo inicial de errores, etc.

Por lo tanto, la práctica común es crear clases especiales para trabajar con la base de datos. Estas clases se denominan DAO, Objeto de acceso a datos. Su tarea es ocultar todas las complejidades de trabajar con la base de datos y proporcionar una interfaz hermosa y conveniente para el exterior.

Ejemplo:

public class EmployeeDAO {

   public List<Employee> getEmployeeList(int from, int count) {
   	String hqlQuery = “from Employee;
   	Query<Employee> query = session.createQuery(hqlQuery, Employee.class);
   	query.setFirstResult(from);
   	query.setMaxResults(count);
   	return query.getResultList();
  }

	public int getEmployeeCount() {
	     String hqlQuery = “select count(*) from Employee;
     	Query<Integer> query = session.createQuery(hqlQuery, Integer.class);
     	return query.getSingleResult();
   }

	public Employee getEmployeeByUniqName(String name) {
	     String hqlQuery = “from Employee where name = :name”;
     	Query<Integer> query = session.createQuery(hqlQuery, Employee.class);
     	query.setParameterr(“name”, name);
     	return query.getSingleResult();
   }
}

Tenemos una clase EmployeeDAO , con la ayuda de la cual obtenemos objetos de tipo Employee de la base de datos. La clase en sí, aunque está repleta de anotaciones, no contiene métodos para guardarse en la base de datos.

Beneficios de la DAO

Las ventajas de este enfoque son muchas:

Primero, hemos ocultado completamente el trabajo con la base de datos en la clase DAO. Si decide en el futuro reescribir todas las consultas de HQL a Criteria API o Native Query, esto no afectará el código fuera de esta clase de ninguna manera.

En segundo lugar, puede complicar el comportamiento de estos métodos. Puede agregar almacenamiento en caché, eventos, validación de parámetros. Todo esto estará oculto del código externo.

En tercer lugar, si necesita un método que aún no existe, simplemente agréguelo aquí. Por ejemplo, necesito un método que devuelva todas las tareas de usuario que ya hayan expirado. Entonces solo haré esto:

public class EmployeeDAO {

   public List<Task> getExpiredTasks(int userId, int from, int count) {
   	String hqlQuery = “from Task where task.user.id = :id and deadline < curdate();
   	Query<Task> query = session.createQuery(hqlQuery, Task.class);
   	query.setFirstResult(from);
   	query.setMaxResults(count);
   	return query.getResultList();
  }

   public int getExpiredTasksCount(int userId) {
   	String hqlQuery = “select count(*) from Task where task.user.id = :id and deadline < curdate();
   	Query<Integer> query = session.createQuery(hqlQuery, Integer.class);
   	return query.getSingleResult();
  }
}

Agregué dos métodos a la clase:

  • getExpiredTasksCount() - devuelve el número de tareas caducadas para el usuario
  • getExpiredTasks() - devuelve una lista de tareas caducadas para el usuario

Necesito métodos, los agregué. Y puedo usarlo de inmediato. Los optimizaré más tarde.

Además, estos métodos se pueden cubrir con pruebas unitarias antes de la reescritura y optimizaciones, por lo que sabremos que el trabajo con la base de datos se ha mantenido igual que antes.

Enfoque estándar

Muy a menudo, las clases DAO tienen métodos que son iguales. Por ejemplo, estos:

T getById (identificación larga final) Obtener un objeto por su id
List<T> getItems (int from, int count) Obtener una lista de objetos dentro de un rango dado
Lista<T> obtenerTodos () Obtener todos los objetos de un tipo dado
int obtenerCuenta () Averiguar la cantidad de objetos
T save (entidad T final) Guardar objeto en la base de datos
Actualización T (entidad T final) Actualizar objeto en la base de datos
void delete (entidad T final) Eliminar un objeto de la base de datos
void deleteById (identificación larga final de la entidad) Eliminar objeto de la base de datos por id

Estos métodos se encuentran en casi todas las clases DAO del mundo. Ahora, si hay algún tipo de clase DAO, entonces con un 90% de probabilidad tendrá tales métodos.

Sí, puede haber otros, pero también los habrá. Porque es muy conveniente. Y te permite no interactuar con la base o Hibernate directamente.

Y si hay métodos idénticos, ¿qué necesitan? Así es, ponlo en la clase base.

Se ve algo como esto:

public abstract class AbstractHibernateDao<T > {
    private final Class<T> clazz;
    private SessionFactory sessionFactory;

    public AbstractHibernateDao(final Class<T> clazzToSet)   {
    	this.clazz = clazzToSet;
    }

    public T getById(final long id) {
    	return (T) getCurrentSession().get(clazz, id);
    }

    public List<T> getItems(int from, int count) {
    	Query query = getCurrentSession().createQuery(clazz , "from " + clazz.getName())
    	query.setFirstResult(offset);
    	query.setMaxResults(count);
  	  return query.singleResult();
    }

    public List<T> findAll() {
    	return getCurrentSession().createQuery(clazz, "from " + clazz.getName()).list();
    }

    public T create(final T entity) {
    	getCurrentSession().saveOrUpdate(entity);
    	return entity;
    }

    public T update(final T entity) {
    	return (T) getCurrentSession().merge(entity);
    }

    public void delete(final T entity) {
    	getCurrentSession().delete(entity);
    }

    public void deleteById(final long entityId) {
    	final T entity = getById(entityId);
    	delete(entity);
    }

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

Y luego nuestro EmployeeDAO se verá así:

public class EmployeeDAO extends AbstractHibernateDAO<Employee> {

   public EmployeeDAO (){
  	super(Employee.class );
   }
}

Y TaskDAO es así:

public class TaskDAO extends AbstractHibernateDAO<Task> {

   public TaskDAO (){
  	super(Task.class );
   }
}

Y ambas clases tendrán todos los métodos que declaramos en AbstractHibernateDAO . La unificación es muy conveniente y práctica.