SpringDataJPAと名前付きエンティティグラフ
1. 概要
簡単に言えば、エンティティグラフはJPA 2.1でクエリを記述する別の方法です。これらを使用して、よりパフォーマンスの高いクエリを作成できます。
このチュートリアルでは、簡単な例を使用して、 Spring DataJPAを使用してエンティティグラフを実装する方法を学習します。
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
public class Characteristic {
@Id
private Long id;
private String type;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn
private Item item;
//Getters and Setters
}
コードからわかるように、 ItementityのcharacteristicsフィールドとCharacteristicエンティティのitemフィールドの両方が読み込まれます。 fetchパラメーターを怠惰に使用します。 したがって、ここでの目標は、実行時にそれらを熱心にロードすることです。
3. エンティティグラフ
Spring Data JPAでは、@NamedEntityGraphと@EntityGraphアノテーションの組み合わせを使用してエンティティグラフを定義できます。 または、@EntityGraphアノテーションのattributePaths引数のみを使用してアドホックエンティティグラフを定義することもできます。
それがどのように行われるか見てみましょう。
3.1. @NamedEntityGraphを使用
まず、JPAの @NamedEntityGraphアノテーションをアイテムエンティティに直接使用できます。
@Entity
@NamedEntityGraph(name = "Item.characteristics",
attributeNodes = @NamedAttributeNode("characteristics")
)
public class Item {
//...
}
次に、@EntityGraphアノテーションをリポジトリメソッドの1つにアタッチできます。
public interface ItemRepository extends JpaRepository<Item, Long> {
@EntityGraph(value = "Item.characteristics")
Item findByName(String name);
}
コードが示すように、以前にItemエンティティで作成したエンティティグラフの名前を@EntityGraphアノテーションに渡しました。 メソッドを呼び出すとき、それはSpringDataが使用するクエリです。
@EntityGraphアノテーションのtype引数のデフォルト値はEntityGraphType.FETCHです。 これを使用すると、SpringDataモジュールは指定された属性ノードにFetchType.EAGER戦略を適用します。 また、その他の場合は、FetchType.LAZY戦略が適用されます。
したがって、この場合、 @OneToMany アノテーションのデフォルトのフェッチ戦略は怠惰ですが、characteristicsプロパティは熱心にロードされます。
ここでの1つの落とし穴は、定義されたフェッチ戦略がEAGERの場合、その動作を LAZYに変更できないことです。これは、後続の操作で熱心にフェッチされたデータが必要になる可能性があるため、仕様によるものです。実行中の後のポイント。
3.2. @NamedEntityGraphなし
または、attributePaths。を使用してアドホックエンティティグラフを定義することもできます。
Item親を熱心にロードするCharacteristicsRepositoryにアドホックエンティティグラフを追加しましょう。
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 アノテーションなしで生成されたクエリは、特性エンティティのプロパティをロードしていないことがはっきりとわかります。その結果、
最後に、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. 結論
このチュートリアルでは、SpringDataでJPAエンティティグラフを使用する方法を学習しました。 Spring Dataを使用すると、さまざまなエンティティグラフにリンクされた複数のリポジトリメソッドを作成できます。
この記事の例は、GitHubでから入手できます。