Подтвердить что ты не робот

Использование графа сущности JPA со сложными условиями

У меня есть проект, построенный на Spring MVC + JPA + Hibernate. Я использую диаграммы сущностей (JPA 2.1) для определения данных для извлечения из базы данных, как в примере ниже.

EntityGraph<Company> entityGraph = entityManager.createEntityGraph(Company.class);
entityGraph.addAttributeNodes("reviews");

Map<String, Object> hints = new HashMap<String, Object>();
hints.put("javax.persistence.loadgraph", entityGraph);

Company company = entityManager.find(Company.class, companyId, hints);

Мой объект Review имеет связь с объектом Company (ManyToOne).

Здесь я просто извлекаю объект Company с заполненной коллекцией reviews. Это хорошо работает в сценариях, подобных описанным выше. Но что, если я хочу получить все или некоторые обзоры данной компании? То есть объекты Review, которые связаны с компанией с данным идентификатором. Я хочу List<Review> вместо объекта Company с List<Review>. Это всего лишь пример - в основном я ищу больше гибкости, чем просто поиск объекта на основе первичного ключа. Я могу сделать это с помощью HQL без проблем, но тогда мне придется писать несколько похожих запросов, в зависимости от того, какие данные мне нужны в конкретном контексте.

Метод find на javax.persistence.EntityManager просто позволяет запросить объект на основе первичного ключа. Но возможно ли использовать графики сущностей в более сложных сценариях, например. с объектами Criteria или запросами HQL? Например, поиск объектов с другими условиями, чем с помощью первичного ключа, возможно, даже для условий ассоциации.

Надеюсь, я поняла. Спасибо заранее!

4b9b3361

Ответ 1

То, что вы ищете, возможно, не EntityGraph s, но JPA Query (либо JPQL в форме NamedQuery, либо CriteriaQuery). Все это является частью спецификации JPA.

Итак, в основном вы можете:

  • Аннотировать все сущности clas с помощью @NamedQueries, чтобы указать запросы JPQL. Их преимущество заключается в том, что их синтаксис проверяется при развертывании (развертывание не будет выполнено, если, например, NamedQueries получит доступ к отсутствующим свойствам), и они многократно используются, а недостатком является: они статически определены (но, конечно, принимают параметры).
  • Построить во время выполнения запросов JPQL с EntityManager. Я использую NamedQueries чаще, чем запросы времени выполнения из-за вышеупомянутых преимуществ.
  • Используйте API критериев, который имеет то преимущество, что они безопасны по типу при подключении/поиске/добавлении условий/воспроизведении с реальными объектами Java.

Теперь о EntityGraph s: они просто помогают, поэтому вы получите дополнительные поля из запроса (независимо от того, используете ли вы EntityManager.find() с параметром карты дополнительных свойств или Query.setHints()). Вы также можете использовать подграфы для более сложных ситуаций. Проверьте этот и этот пример.

Ответ 2

Как вы заметили:

Я могу сделать это с помощью HQL без проблем, но тогда мне придется писать несколько похожих запросов, в зависимости от того, какие данные мне нужны в конкретном контекст.

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

public interface CompanyRepository{

    List<Review> findAll(Criteria criteria, FetchPlan fetchPlan);
}

Проект Spring Data действительно может заставить нас участвовать в этом, но не в настоящее время, (хотя есть некоторые обсуждения вокруг недостающей части: см. ниже).

В настоящий момент это первая часть:

public interface CompanyRepository{

    List<Review> findAll(Criteria criteria);

}

либо с помощью шаблона Спецификации (http://docs.spring.io/spring-data/jpa/docs/1.8.0.M1/reference/html/#specifications), либо, проще, используя API-интерфейс QueryDSL, альтернативный API-интерфейсу JPA.

Используя подход QueryDSL, мы можем создать определение репозитория следующим образом:

public interface ReviewRepository extends CrudRepository<Review, Long>, QueryDslPredicateExecutor<Review>{

}

Теперь и без создания реализации (созданной каркасом) или написания кода мы можем назвать его ниже, с любой комбинацией атрибутов:

Review review = respository.findOne();
Iterable<Review> reviews = respository.findAll(QReview.review.created.eq(someDate));
Iterable<Review> reviews = respository.findAll(QReview.review.created.eq(someDate).and(QReview.review.creator.forename.eq("Jim"));
Iterable<Review> reviews = respository.findAll(QReview.review.created.eq(someDate).and(QReview.review.creator.forename.eq("Jim").and(QReview.review.company.name.eq("Amazon"));

и т.д....

где QReview - это тип запроса, созданный QueryDSL-библиотекой, и дающий вам строго типизированные запросы, а методы findOne (предикат предикатов) и findAll (Precicate predicate) наследуются от:

http://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/querydsl/QueryDslPredicateExecutor.html

Это дает вам много для очень небольшого (нулевого) кода, кроме создания определений интерфейса, но все равно потребует дополнительного (субоптимальный с точки зрения взаимодействия БД) механизм обработки ленивой загрузки, т.е. один из механизмов, выделенных в других ваших недавних вопрос и который привел к этому.

Однако я не вижу, почему Spring Data не удалось обновить для обработки динамической спецификации EntityGraphs, и действительно, некоторые обсуждения вокруг этого, поэтому он может быть в стадии разработки:

http://forum.spring.io/forum/spring-projects/data/108202-custom-fetch-groups-with-spring-data-jpa-possible

возможно, стоит собрать JIRA, чтобы узнать, планируют ли это что-то или спрашивают

https://stackoverflow.com/users/18122/oliver-gierke

непосредственно.

Некоторая поддержка была добавлена ​​в Spring Data для новой функции JPA 2.1 EntityGraphb, но я не вижу, что ее можно заставить работать с общим методом запросов, который мы хотим здесь:

http://docs.spring.io/spring-data/jpa/docs/1.8.0.M1/reference/html/#jpa.entity-graph