Spring Data JPAおよび名前付きエンティティグラフ

1. 概要

*簡単に言えば、https://www.baeldung.com/jpa-entity-graph [Entity Graphs]は、JPA 2.1でクエリを記述する別の方法です。*これらを使用して、パフォーマンスの高いクエリを作成できます。
このチュートリアルでは、簡単な例を通して、https://www.baeldung.com/the-persistence-layer-with-spring-data-jpa [Spring Data JPA]を使用してエンティティグラフを実装する方法を学習します。

2. エンティティ

まず、複数の特性を持つ_Item_というモデルを作成しましょう。
@Entity
public class Item {

    @Id
    private Long id;
    private String name;

    @OneToMany(mappedBy = "item")
    private List<Characteristic> characteristics = new ArrayList<>();

    // getters and setters
}
C__haracteristic__ entityを定義しましょう:
@Entity
public class Characteristic {

    @Id
    private Long id;
    private String type;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn
    private Item item;

    //Getters and Setters
}
コードでわかるように、_Item_エンティティの_characteristics_フィールドと_Characteristic_エンティティの_item_フィールドの両方は、_fetch_パラメーターを使用して遅延ロードされます。 したがって、*ここでの目標は、実行時にそれらを熱心にロードすることです*。

3. エンティティグラフ

Spring Data JPAでは、_ @ NamedEntityGraph_と_ @ EntityGraph_アノテーションの組み合わせ*を使用してエンティティグラフを定義できます。 または、_ @ EntityGraph_注釈の* _attributePaths_引数のみでアドホックエンティティグラフを定義することもできます。
それがどのように行われるかを見てみましょう。

* 3.1。 _ @ NamedEntityGraph_ *を使用

まず、JPAの_ @ NamedEntityGraph_アノテーションを_Item_エンティティで直接使用できます。
@Entity
@NamedEntityGraph(name = "Item.characteristics",
    attributeNodes = @NamedAttributeNode("characteristics")
)
public class Item {
    //...
}
その後、リポジトリメソッドの1つに_ @ EntityGraph_注釈を添付できます。
public interface ItemRepository extends JpaRepository<Item, Long> {

    @EntityGraph(value = "Item.characteristics")
    Item findByName(String name);
}
コードが示すように、以前に_Item_エンティティで作成したエンティティグラフの名前を_ @ EntityGraph_アノテーションに渡しました。 メソッドを呼び出すとき、それはSpring Dataが使用するクエリです。
  • _ @ EntityGraph_アノテーションのtype引数のデフォルト値は_EntityGraphType.FETCH_ *です。 これを使用すると、Spring Dataモジュールは、指定された属性ノードに_FetchType.EAGER_戦略を適用します。 その他の場合は、_FetchType.LAZY_戦略が適用されます。

    したがって、このケースでは、_ @ OneToMany_アノテーションのデフォルトのフェッチ戦略が遅延であっても、_characteristics_プロパティが積極的にロードされます。
    ここでの1つの落とし穴は、定義された_fetch_戦略が__EAGERの場合、__thenの動作を_ * LAZY *に変更できないことです。これは、後続の操作が実行中に後から積極的にフェッチされるデータを必要とする可能性があるためです

* 3.2。 _ @ NamedEntityGraph_ *なし

**または、アドホックエンティティグラフも定義できます。** with _attributePaths._
_CharacteristicsRepository_にアドホックエンティティグラフを追加して、_Item_親を積極的にロードします。
public interface CharacteristicsRepository
  extends JpaRepository<Characteristic, Long> {

    @EntityGraph(attributePaths = {"item"})
    Characteristic findByType(String type);
}
これにより、* Characteristic_エンティティの_item_プロパティが熱心にロードされます。*エンティティがこのプロパティの遅延ロード戦略を宣言している場合でも*。
これは、既存の名前付きエンティティグラフを参照する代わりに、エンティティグラフをインラインで定義できるため便利です。

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_アノテーションを使用して定義されたエンティティグラフを使用します。
Hibernateによって生成されたSQLを見てみましょう。
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_注釈なしで生成されたクエリが_Characteristic_エンティティのプロパティをロードしていないことを明確に観察できます。*結果として、_Item_エンティティのみをロードします。
最後に、2番目のテストの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. 結論

このチュートリアルでは、Spring DataでJPAエンティティグラフを使用する方法を学びました。 Spring Dataでは、*異なるエンティティグラフにリンクされた複数のリポジトリメソッドを作成できます*。
この記事の例は、https://github.com/eugenp/tutorials/tree/master/persistence-modules/spring-data-jpa-2 [GitHub上]で入手できます。