Статьи

Шаблоны реализации JPA: получение объектов

В прошлый раз я говорил о том, как сохранить сущность . И как только мы сохранили сущность, мы также хотели бы получить ее. По сравнению с сохранением сущностей, поиск сущностей на самом деле довольно прост. Так просто, я сомневался, будет ли много смысла писать этот блог ;-). Однако при написании кода для этого мы использовали несколько хороших шаблонов. И мне интересно услышать, какие шаблоны вы используете для извлечения сущностей. 

По сути, есть два способа получить объект с помощью JPA:


Объект А Запрос также может быть создан путем обращения к именованному запросу ( с использованием EntityManager.createNamedQuery ), либо путем передачи в запросе SQL ( с использованием одного из трех трех ароматов из EntityManager.createNativeQuery). И хотя название подразумевает иное, запрос также может быть использован для выполнения оператора обновления или удаления .

Именованный запрос может показаться хорошим способом сохранить запрос с сущностями, которые он запрашивает, я обнаружил, что это не очень хорошо работает. Большинству запросов необходимо задать параметры с помощью одного из вариантов Query.setParameter . Хранение запроса и кода, который устанавливает эти параметры вместе, облегчает их понимание. Вот почему я держу их вместе в DAO и избегаю использования именованных запросов.

Соглашение, которое я считаю полезным, состоит в том, чтобы различать поиск объекта и получение объекта. В первом случае ноль возвращается, когда сущность не может быть найдена, тогда как во втором случае выдается исключение. Использование последнего метода, когда ваш код ожидает присутствие объекта, предотвращает появление всплывающих окон NullPointerException.

Поиск и получение одной сущности по идентификатору

Реализация этого шаблона для базового класса JpaDao, который мы обсуждали несколько блогов назад, может выглядеть следующим образом (я включил метод find для контраста):

public E findById(K id) {
	return entityManager.find(entityClass, id);
}
 
public E getById(K id) throws EntityNotFoundException {
	E entity = entityManager.find(entityClass, id);
	if (entity == null) {
		throw new EntityNotFoundException(
			"Entity " + entityClass.getName() + " with id " + id + " not found");
	}
	return entity;
}

Конечно, вам также нужно добавить этот новый метод в интерфейс Dao :

E getById(K id);

Поиск и получение одного объекта с запросом

Подобное различие может быть сделано, когда мы используем запрос для поиска единственного объекта. Приведенный ниже метод findOrderSubmittedAt возвращает ноль, если сущность не может быть найдена запросом. Метод getOrderSubmittedAt генерирует исключение NoResultException . Оба метода генерируют исключение NonUniqueResultException, если возвращается более одного результата. Чтобы метод getOrderSubmittedAt соответствовал методу findById, мы могли бы сопоставить исключение NoResultException и EntityNotFoundException . Но поскольку существуют оба непроверенных исключения, в этом нет реальной необходимости.

Поскольку эти методы применяются только к объекту Order, в JpaOrderDao есть часть :

public Order findOrderSubmittedAt(Date date) throws NonUniqueResultException {
	Query q = entityManager.createQuery(
		"SELECT e FROM " + entityClass.getName() + " e WHERE date = :date_at");
	q.setParameter("date_at", date);
	try {
		return (Order) q.getSingleResult();
	} catch (NoResultException exc) {
		return null;
	}
}
 
public Order getOrderSubmittedAt(Date date) throws NoResultException, NonUniqueResultException {
	Query q = entityManager.createQuery(
		"SELECT e FROM " + entityClass.getName() + " e WHERE date = :date_at");
	q.setParameter("date_at", date);
	return (Order) q.getSingleResult();
}

Добавление правильных методов в интерфейс OrderDao оставлено читателю в качестве упражнения.;-)

Поиск нескольких объектов с помощью запроса

Конечно, мы также хотим иметь возможность найти более одной сущности. В этом случае я обнаружил, что нет никакого полезного различия между получением и поиском . Метод findOrdersSubmittedSince просто возвращает список найденных сущностей. Этот список может содержать ноль, одну или несколько сущностей. Смотрите следующий код:

public List<Order> findOrdersSubmittedSince(Date date) {
	Query q = entityManager.createQuery(
			"SELECT e FROM " + entityClass.getName() + " e WHERE date >= :date_since");
	q.setParameter("date_since", date);
	return (List<Order>) q.getResultList();
}

Внимательные читатели заметят, что этот метод уже присутствовал в первой версии JpaOrderDao .

Поэтому, хотя поиск сущностей довольно прост, есть несколько шаблонов, которые вы можете использовать при реализации методов поиска и получения. Конечно, мне было бы интересно узнать, как вы справляетесь с этим в своем коде.

PS JPA 1.0 пока не поддерживает его, но JPA 2.0 будет включать Criteria API . Criteria API позволит вам динамически создавать запросы JPA. Критерии запросов являются более гибкими, чем строковые запросы, поэтому вы можете строить их в зависимости от ввода в форме поиска. А поскольку вы определяете их с помощью доменных объектов, их легче поддерживать, поскольку ссылки на доменные объекты автоматически реорганизуются. К сожалению, API Criteria требует, чтобы вы ссылались на свойства вашей сущности по имени, поэтому ваша IDE не поможет вам, когда вы их переименуете.

С http://blog.xebia.com