Въведение в DAO

Когато работите с база данни чрез JDBC or дори чрез Hibernate, codeът често се оказва по-тромав, отколкото бихме искали. Заявка към база данни често съдържа:

  • потвърждаване на данни
  • задаване на параметри на заявката
  • Избор на HQL заявка в зависимост от параметрите на заявката
  • създаване на заявка с помощта на API на критериите
  • настройки за кеширане
  • първоначална обработка на грешки и др.

Затова масовата практика е да се създават специални класове за работа с базата данни. Такива класове се наричат ​​DAO, Data Access Object. Тяхната задача е да скрият всички сложности на работа с базата данни и да осигурят красив и удобен интерфейс навън.

Пример:

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

Имаме клас EmployeeDAO , с помощта на който получаваме обекти от тип Employee от базата данни. Самият клас, въпреки че е пълен с анотации, не съдържа методи за самозапаметяване в базата данни.

Предимства на DAO

Този подход има много предимства:

Първо, напълно скрихме работата с базата данни в класа DAO. Ако решите в бъдеще да пренапишете всички заявки от HQL към Criteria API or Native Query, това по ниHowъв начин няма да засегне codeа извън този клас.

Второ, можете да усложните поведението на тези методи. Можете да добавите кеширане, събития, валидиране на параметри. Всичко това ще бъде скрито от външния code.

Трето, ако имате нужда от метод, който все още не съществува, просто го добавете тук. Например, имам нужда от метод, който ще върне всички потребителски задачи, които вече са изтекли. Тогава просто ще направя това:

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

Добавих два метода към класа:

  • getExpiredTasksCount() - връща броя на изтеклите задачи за потребителя
  • getExpiredTasks() - връща списък с изтекли задачи за потребителя

Имам нужда от методи - добавих ги. И мога да го използвам веднага. Ще ги оптимизирам по-късно.

Освен това тези методи могат да бъдат покрити с модулни тестове преди пренаписване и оптимизации, така че ще знаем, че работата с базата данни е останала същата, Howто беше.

Стандартен подход

Много често DAO класовете имат методи, които са еднакви. Например тези:

T getById (краен дълъг идентификатор) Вземете обект по неговия идентификатор
List<T> getItems (int from, int count) Вземете списък с обекти в даден диапазон
List<T> getAll () Вземете всички обекти от даден тип
int getCount () Разберете броя на обектите
T save (окончателен T обект) Запазване на обект в база данни
T актуализация (окончателен T обект) Актуализирайте обект в базата данни
невалидно изтриване (окончателен T обект) Изтриване на обект от базата данни
void deleteById (краен дълъг entityId) Изтриване на обект от база данни по id

Тези методи се намират в почти всеки DAO клас в света. Сега, ако има няHowъв вид DAO клас, тогава с 90% вероятност той ще има такива методи.

Да, може да има и други, но ще има и такива. Защото е много удобно. И ви позволява да не взаимодействате директно с базата or хибернация.

И ако има идентични методи, тогава от Howво се нуждаят? Точно така, поставете го в базовия клас.

Изглежда нещо подобно:

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

И тогава нашият EmployeeDAO ще изглежда така:

public class EmployeeDAO extends AbstractHibernateDAO<Employee> {

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

И TaskDAO е така:

public class TaskDAO extends AbstractHibernateDAO<Task> {

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

И двата класа ще имат всички методи, които декларирахме в AbstractHibernateDAO . Обединяването е много удобно и практично.