Introduzione a DAO

Quando si lavora con un database tramite JDBC o anche tramite Hibernate, il codice spesso risulta essere più macchinoso di quanto vorremmo. Una query di database spesso contiene:

  • convalida dei dati
  • impostazione dei parametri di richiesta
  • Selezione della query HQL in base ai parametri della query
  • costruire una query utilizzando l'API Criteria
  • impostazioni di memorizzazione nella cache
  • gestione iniziale degli errori, ecc.

Pertanto, la pratica comune consiste nel creare classi speciali per lavorare con il database. Tali classi sono chiamate DAO, Data Access Object. Il loro compito è nascondere tutte le complessità del lavoro con il database e fornire un'interfaccia bella e comoda verso l'esterno.

Esempio:

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();
   }
}

Abbiamo una classe EmployeeDAO , con l'aiuto della quale otteniamo oggetti di tipo Employee dal database. La classe stessa, sebbene piena di annotazioni, non contiene metodi per salvarsi nel database.

Vantaggi di DAO

Ci sono molti vantaggi in questo approccio:

Innanzitutto, abbiamo completamente nascosto il lavoro con il database nella classe DAO. Se in futuro decidi di riscrivere tutte le query da HQL a Criteria API o Native Query, ciò non influirà in alcun modo sul codice al di fuori di questa classe.

In secondo luogo, puoi complicare il comportamento di questi metodi. È possibile aggiungere memorizzazione nella cache, eventi, convalida dei parametri. Tutto questo sarà nascosto dal codice esterno.

In terzo luogo, se hai bisogno di un metodo che non esiste ancora, basta aggiungerlo qui. Ad esempio, ho bisogno di un metodo che restituisca tutte le attività utente che sono già scadute. Allora farò solo questo:

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();
  }
}

Ho aggiunto due metodi alla classe:

  • getExpiredTasksCount() - restituisce il numero di attività scadute per l'utente
  • getExpiredTasks() - restituisce un elenco di attività scadute per l'utente

Ho bisogno di metodi: li ho aggiunti. E posso usarlo subito. Li ottimizzerò in seguito.

Inoltre, questi metodi possono essere coperti con test unitari prima della riscrittura e delle ottimizzazioni, quindi sapremo che il lavoro con il database è rimasto lo stesso di prima.

Approccio standard

Molto spesso, le classi DAO hanno metodi uguali. Ad esempio, questi:

T getById (ID lungo finale) Ottieni un oggetto dal suo id
List<T> getItems (int from, int count) Ottieni un elenco di oggetti all'interno di un determinato intervallo
Lista<T> getAll () Ottieni tutti gli oggetti di un determinato tipo
int getCount () Scopri il numero di oggetti
T save (entità T finale) Salva oggetto nel database
Aggiornamento T (entità T finale) Aggiorna oggetto nel database
void delete (entità T finale) Elimina un oggetto dal database
void deleteById (final long entityId) Elimina oggetto dal database per id

Questi metodi si trovano in quasi tutte le classi DAO del mondo. Ora, se esiste una sorta di classe DAO, con una probabilità del 90% avrà tali metodi.

Sì, potrebbero essercene altri, ma ci saranno anche quelli. Perché è molto conveniente. E ti consente di non interagire direttamente con la base o Hibernate.

E se esistono metodi identici, di cosa hanno bisogno? Esatto, mettilo nella classe base.

Assomiglia a questo:

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();
    }
}

E poi il nostro EmployeeDAO sarà simile a questo:

public class EmployeeDAO extends AbstractHibernateDAO<Employee> {

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

E TaskDAO è così:

public class TaskDAO extends AbstractHibernateDAO<Task> {

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

Ed entrambe queste classi avranno tutti i metodi che abbiamo dichiarato su AbstractHibernateDAO . L'unificazione è molto comoda e pratica.