В JPA Entities - это хорошие аннотированные простые старые Java-объекты. Но я не нашел хорошего способа взаимодействовать с ними и с базой данных.
В моем текущем приложении мой базовый дизайн всегда заключается в том, чтобы в качестве первичного ключа всегда был идентификатор на основе последовательности, поэтому мне обычно приходится искать объекты по другим свойствам, кроме PK.
И для каждой Entity у меня есть EJB без сохранения состояния
@Stateless
public class MyEntApiBean implements MyEntApi {
@PersistenceContext(unitName = "xxx") @Inject EntityManager entityManager;
с методами запроса, которые все являются вариациями
/**
* @return A List of all MyEnts that have some property
* @param someProp some property
*/
public List<MyEnt> getAllMyEntsFromProp(final String someProp) {
try {
final Query query = entityManager.createQuery("select me from MyEnt me where me.someProp = :someProp");
query.setParameter("someProp", someProp);
return query.getResultList();
} catch(final NoResultException nre) {
log.warn("No MyEnts found");
}
return new ArrayList<MyEnt>();
}
Так:
Я действительно ненавижу наличие этих методов в EJB, потому что они кажутся принадлежащими самим объектам, а локальные интерфейсы EJB меня до чертиков раздражают.
Я ненавижу дублирование, которое у меня есть в каждом методе с «try, createQuery, getResultList, catch, log, return» (в основном из-за отсутствия замыканий или «with statement» или чего-то подобного в Java).
Есть ли у кого-нибудь предложение лучшего способа взаимодействия с объектами и базой данных, который решает одну или обе мои проблемы?
В настоящее время я подумываю о некоторых базовых методах с обобщениями и отражением, чтобы получить некоторые общие методы запросов, чтобы уменьшить дублирование (проблема 2) (позже я поставлю прототип для обзора).
Спасибо, Андерс




Попробуйте Шов. Объекты запроса выполняет большую часть работы за вас, и их легко расширить. Или вы всегда можете реализовать аналогичный шаблон.
В общем, Seam делает много полезных вещей, чтобы преодолеть разрыв между JPA, вашим просмотром и бизнес-уровнями. Чтобы Seam был полезным, необязательно использовать JSF.
Если вы выполняете много текстовых поисков, возможно, вам также стоит рассмотреть некоторую структуру индексации, такую как Компас.
Я не знаю, подходит ли это вашему приложению, но если да, то он может улучшить дизайн кода и производительность.
На самом деле я использую Шов. И предложение объекта Query привело меня к поиску Hibernates Критерии запросов (Query By Example) функциональность. Кажется, это очень похоже на то, что я искал.
Может, в базовом классе и с черта дженериков ....?
Вы излишне многословны. Во-первых, getResultList () не генерирует исключение, когда строки не возвращаются (по крайней мере, не в Eclipse или Toplink - я не могу представить, чтобы другой провайдер был другим). getSingleResult () - нет, getResultList () - нет. Кроме того, вы можете использовать шаблон строителя так:
@SuppressWarnings("unchecked")
public List<MyEnt> getAllMyEntsFromProp(final String someProp) {
return entityManager.createQuery("select me from MyEnt me where me.someProp = :someProp")
.setParameter("someProp", someProp);
.getResultList();
}
должно быть достаточно для возврата списка результатов, если он есть, или пустого списка, если его нет. Обратите внимание на две вещи:
@SuppressWarnings ("unchecked") не требуется, но он избавляет от неизбежного в противном случае предупреждения при преобразовании неуниверсального результата List из getResultList () в общий List; и
Вероятно, стоит заменить вызов createQuery () на @NamedQuery на MyEnt (обычно). Во-первых, это позволит выполнять проверку во время развертывания и другие полезные вещи.
Его достаточно кратко и полно.
Мойн!
Вот моя версия для отдельных результатов (я использую ее в своих настольных JPA-приложениях с основами TopLink):
public class JPA {
@SuppressWarnings ("unchecked")
public static <T> T querySingle(
EntityManager em,
Class<T> clazz,
String namedQuery,
Pair... params)
{
Query q = em.createNamedQuery(namedQuery);
for (Pair pair : params) {
q.setParameter(pair.key, pair.value);
}
List<T> result = q.getResultList();
if ( result.size() == 0 ) {
return null;
}
if ( result.size() == 1 ) {
return result.get(0);
}
throw new
IllegalStateException(
"To many result rows for query: "
+ namedQuery
+ " where "
+ Arrays.toString(params));
}
public static class Pair {
String key;
Object value;
public static Pair param (String key, Object value) {
return new Pair (key, value);
}
public Pair (String key, Object value) {
this.key = key;
this.value = value;
}
@Override
public String toString() {
return key + " = " + value;
}
}
}
И использование:
import static org.sepix.JPA.*;
...
String id = ...
Customer customer = querySingle (em, Customer.class,
"Customer.findByID", Pair.param ("id", id));
или же:
String inquiryID = ...
Boolean current = Boolean.TRUE;
Inquiry inq = querySingle (em, Inquiry.class,
"Inquiry.findCurrent",
Pair.param ("inquiry", inquiryID),
Pair.param ("current", current));
наилучшие пожелания, Джош.
Я предпочитаю использовать Spring JpaDaoSupport, который помогает справляться с JPA. Хороший пример - http://github.com/rafalrusin/jpaqb/blob/master/src/test/java/jpaqb/CarDao.java.
Хорошее разделение логики - наличие класса DAO (объект доступа к данным) и DTO (объект передачи данных). DAO обычно содержит все необходимые запросы, а DTO - это сущности с полями.