Introducere în DAO

Când lucrați cu o bază de date prin JDBC sau chiar prin Hibernate, codul se dovedește adesea a fi mai greoi decât ne-am dori. O interogare de bază de date conține adesea:

  • data validarii
  • setarea parametrilor de solicitare
  • Selectarea interogării HQL în funcție de parametrii de interogare
  • construirea unei interogări folosind API-ul Criteria
  • setări de cache
  • tratarea erorilor inițiale etc.

Prin urmare, practica comună este de a crea clase speciale pentru lucrul cu baza de date. Astfel de clase se numesc DAO, Data Access Object. Sarcina lor este să ascundă toate complexitățile lucrului cu baza de date și să ofere o interfață frumoasă și convenabilă către exterior.

Exemplu:

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

Avem o clasă EmployeeDAO , cu ajutorul căreia obținem obiecte de tip Employee din baza de date. Clasa în sine, deși plină cu adnotări, nu conține metode de salvare în baza de date.

Beneficiile DAO

Există multe avantaje ale acestei abordări:

În primul rând, am ascuns complet lucrul cu baza de date în clasa DAO. Dacă decideți în viitor să rescrieți toate interogările din HQL în Criteria API sau Native Query, acest lucru nu va afecta în niciun fel codul din afara acestei clase.

În al doilea rând, puteți complica comportamentul acestor metode. Puteți adăuga stocare în cache, evenimente, validare a parametrilor. Toate acestea vor fi ascunse de codul exterior.

În al treilea rând, dacă aveți nevoie de o metodă care nu există încă, trebuie doar să o adăugați aici. De exemplu, am nevoie de o metodă care să returneze toate sarcinile utilizatorului care au fost deja expirate. Atunci voi face doar asta:

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

Am adăugat două metode la clasă:

  • getExpiredTasksCount() - returnează numărul de sarcini expirate pentru utilizator
  • getExpiredTasks() - returnează o listă de sarcini expirate pentru utilizator

Am nevoie de metode - le-am adăugat. Și îl pot folosi imediat. Le voi optimiza mai târziu.

Mai mult, aceste metode pot fi acoperite cu teste unitare înainte de rescriere și optimizări, așa că vom ști că lucrul cu baza de date a rămas neschimbat.

Abordare standard

Foarte des, clasele DAO au metode care sunt aceleași. De exemplu, acestea:

T getById (ID lung final) Obțineți un obiect după id-ul său
List<T> getItems (int from, int count) Obțineți o listă de obiecte dintr-un interval dat
List<T> getAll () Obțineți toate obiectele de un anumit tip
int getCount () Aflați numărul de obiecte
T salvare (entitate T finală) Salvați obiectul în baza de date
Actualizare T (entitate T finală) Actualizați obiectul în baza de date
ștergere nulă (entitate T finală) Ștergeți un obiect din baza de date
void deleteById (ID final de entitate lung) Ștergeți obiectul din baza de date după id

Aceste metode se găsesc în aproape fiecare clasă DAO din lume. Acum, dacă există un fel de clasă DAO, atunci cu 90% probabilitate va avea astfel de metode.

Da, pot fi și altele, dar vor fi și acestea. Pentru că este foarte convenabil. Și vă permite să nu interacționați direct cu baza sau să Hibernați.

Și dacă există metode identice, atunci de ce au nevoie? Așa e, pune-l în clasa de bază.

Arata cam asa:

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

Și apoi, EmployeeDAO nostru va arăta astfel:

public class EmployeeDAO extends AbstractHibernateDAO<Employee> {

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

Și TaskDAO este așa:

public class TaskDAO extends AbstractHibernateDAO<Task> {

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

Și ambele clase vor avea toate metodele pe care le-am declarat pe AbstractHibernateDAO . Unificarea este foarte convenabilă și practică.