1. Обзор
Проще говоря, Entity Graphs -это еще один способ описания запроса в JPA 2.1. Мы можем использовать их для формулирования более эффективных запросов.
В этом уроке мы узнаем, как реализовать графики сущностей с помощью Spring Data JPA на простом примере.
2. Сущности
Во-первых, давайте создадим модель под названием Элемент который имеет несколько характеристик:
@Entity public class Item { @Id private Long id; private String name; @OneToMany(mappedBy = "item") private Listcharacteristics = new ArrayList<>(); // getters and setters }
Теперь давайте определим сущность C characteristic :
@Entity public class Characteristic { @Id private Long id; private String type; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn private Item item; //Getters and Setters }
Как мы видим в коде, как поле characteristics в сущности Item , так и поле item в сущности Characteristic загружаются лениво с помощью параметра fetch . Итак, наша цель здесь-охотно загружать их во время выполнения.
3. Графы Сущностей
В Spring Data JPA мы можем определить граф сущностей, используя комбинацию @NamedEntityGraph и @EntityGraph аннотаций . Или мы также можем определить специальные графы сущностей только с помощью аргумента attribute Paths аннотации @EntityGraph .
Давайте посмотрим, как это можно сделать.
3.1. С помощью @NamedEntityGraph
Во-первых, мы можем использовать аннотацию JPA @NamedEntityGraph непосредственно на нашем Item entity:
@Entity @NamedEntityGraph(name = "Item.characteristics", attributeNodes = @NamedAttributeNode("characteristics") ) public class Item { //... }
А затем мы можем прикрепить аннотацию @EntityGraph к одному из наших методов репозитория:
public interface ItemRepository extends JpaRepository- { @EntityGraph(value = "Item.characteristics") Item findByName(String name); }
Как показывает код, мы передали имя графа сущностей, который мы создали ранее на Item entity, аннотации @EntityGraph . Когда мы вызываем метод, это строка запроса, которую будут использовать данные.
Значение по умолчанию аргумента type аннотации @EntityGraph равно EntityGraphType.FETCH . Когда мы используем это, модуль Spring Data будет применять тип FetchType.EAGER стратегия на указанных атрибутивных узлах. А для других-тип FetchType.Будет применена стратегия LAZY .
Таким образом, в нашем случае свойство characteristics будет загружаться с нетерпением, даже если стратегия выборки по умолчанию аннотации @OneToMany является ленивой.
Одна загвоздка здесь заключается в том, что если определенная стратегия fetch является НЕТЕРПЕЛИВОЙ, то мы не можем изменить ее поведение на ЛЕНИВОЕ . Это сделано специально, поскольку последующие операции могут нуждаться в нетерпеливо извлеченных данных на более позднем этапе выполнения.
3.2. Без @NamedEntityGraph
Или мы можем определить специальный граф сущностей to, width attribute Paths.
Давайте добавим специальный граф сущностей в наш репозиторий Характеристик , который охотно загружает свой Элемент родитель:
public interface CharacteristicsRepository extends JpaRepository{ @EntityGraph(attributePaths = {"item"}) Characteristic findByType(String type); }
Это будет загружать свойство item объекта Characteristic с нетерпением, даже если наша сущность объявляет стратегию ленивой загрузки для этого свойства.
Это удобно, так как мы можем определить граф сущностей встроенным, а не ссылаться на существующий именованный граф сущностей.
4. Тестовый случай
Теперь когда мы определили наши графы сущностей давайте создадим тестовый случай для его проверки:
@DataJpaTest @RunWith(SpringRunner.class) @Sql(scripts = "/entitygraph-data.sql") public class EntityGraphIntegrationTest { @Autowired private ItemRepository itemRepo; @Autowired private CharacteristicsRepository characteristicsRepo; @Test public void givenEntityGraph_whenCalled_shouldRetrunDefinedFields() { Item item = itemRepo.findByName("Table"); assertThat(item.getId()).isEqualTo(1L); } @Test public void givenAdhocEntityGraph_whenCalled_shouldRetrunDefinedFields() { Characteristic characteristic = characteristicsRepo.findByType("Rigid"); assertThat(characteristic.getId()).isEqualTo(1L); } }
В первом тесте будет использоваться граф сущностей, определенный с помощью аннотации @NamedEntityGraph .
Давайте посмотрим на SQL, сгенерированный Hibernate:
select item0_.id as id1_10_0_, characteri1_.id as id1_4_1_, item0_.name as name2_10_0_, characteri1_.item_id as item_id3_4_1_, characteri1_.type as type2_4_1_, characteri1_.item_id as item_id3_4_0__, characteri1_.id as id1_4_0__ from item item0_ left outer join characteristic characteri1_ on item0_.id=characteri1_.item_id where item0_.name=?
Для сравнения давайте удалим аннотацию @EntityGraph из репозитория и проверим запрос:
select item0_.id as id1_10_, item0_.name as name2_10_ from item item0_ where item0_.name=?
Из этих запросов мы можем ясно видеть, что запрос, сгенерированный без @EntityGraph annotation , не загружает никаких свойств Characteristic entity. В результате он загружает только объект Item .
Наконец, давайте сравним запросы Hibernate второго теста с аннотацией @EntityGraph :
select characteri0_.id as id1_4_0_, item1_.id as id1_10_1_, characteri0_.item_id as item_id3_4_0_, characteri0_.type as type2_4_0_, item1_.name as name2_10_1_ from characteristic characteri0_ left outer join item item1_ on characteri0_.item_id=item1_.id where characteri0_.type=?
И запрос без аннотации @EntityGraph :
select characteri0_.id as id1_4_, characteri0_.item_id as item_id3_4_, characteri0_.type as type2_4_ from characteristic characteri0_ where characteri0_.type=?
5. Заключение
В этом уроке мы узнали, как использовать графики сущностей JPA в Spring Data. С помощью Spring Data мы можем создать несколько методов репозитория, связанных с различными графами сущностей .
Примеры для этой статьи доступны на GitHub .