JPAのINSERTステートメント
1. 概要
このクイックチュートリアルでは、JPAオブジェクトでINSERTステートメントを実行する方法を学習します。
Hibernate全般の詳細については、このトピックの詳細について、Springを使用したJPAの包括的なガイドおよびJPAを使用したSpringデータの紹介を確認してください。
2. JPAでの永続オブジェクト
JPAでは、一時状態から管理状態に移行するすべてのエンティティは、EntityManagerによって自動的に処理されます。
EntityManager は、特定のエンティティがすでに存在するかどうかを確認し、それを挿入するか更新するかを決定します。 この自動管理により、 t JPAで許可されるステートメントは、SELECT、UPDATE、およびDELETEのみです。
以下の例では、この制限を管理および回避するさまざまな方法を見ていきます。
3. 共通モデルの定義
それでは、このチュートリアル全体で使用する単純なエンティティを定義することから始めましょう。
@Entity
public class Person {
@Id
private Long id;
private String firstName;
private String lastName;
// standard getters and setters, default and all-args constructors
}
また、実装に使用するリポジトリクラスを定義しましょう。
@Repository
public class PersonInsertRepository {
@PersistenceContext
private EntityManager entityManager;
}
さらに、 @Transactional アノテーションを適用して、Springによってトランザクションを自動的に処理します。 このように、 EntityManager、でトランザクションを作成して変更をコミットしたり、例外が発生した場合に手動でロールバックを実行したりする必要はありません。
4. createNativeQuery
手動で作成されたクエリの場合、 EntityManager#createNativeQueryメソッドを使用できます。 これにより、JPAでサポートされているものだけでなく、あらゆるタイプのSQLクエリを作成できます。 リポジトリクラスに新しいメソッドを追加しましょう。
@Transactional
public void insertWithQuery(Person person) {
entityManager.createNativeQuery("INSERT INTO person (id, first_name, last_name) VALUES (?,?,?)")
.setParameter(1, person.getId())
.setParameter(2, person.getFirstName())
.setParameter(3, person.getLastName())
.executeUpdate();
}
このアプローチでは、列の名前を含むリテラルクエリを定義し、対応する値を設定する必要があります。
これで、リポジトリをテストできます。
@Test
public void givenPersonEntity_whenInsertedTwiceWithNativeQuery_thenPersistenceExceptionExceptionIsThrown() {
Person person = new Person(1L, "firstname", "lastname");
assertThatExceptionOfType(PersistenceException.class).isThrownBy(() -> {
personInsertRepository.insertWithQuery(PERSON);
personInsertRepository.insertWithQuery(PERSON);
});
}
テストでは、すべての操作でデータベースに新しいエントリを挿入しようとします。 同じidを持つ2つのエンティティを挿入しようとしたため、2番目の挿入操作はPersistenceExceptionをスローして失敗します。
ここでの原則は、SpringDataの@Query。を使用している場合も同じです。
5. 持続
前の例では、挿入クエリを作成しましたが、エンティティごとにリテラルクエリを作成する必要がありました。 このアプローチはあまり効率的ではなく、多くの定型コードが生成されます。
代わりに、EntityManagerのpersistメソッドを使用できます。
前の例のように、カスタムメソッドを使用してリポジトリクラスを拡張しましょう。
@Transactional
public void insertWithEntityManager(Person person) {
this.entityManager.persist(person);
}
これで、アプローチをもう一度テストできます:
@Test
public void givenPersonEntity_whenInsertedTwiceWithEntityManager_thenEntityExistsExceptionIsThrown() {
assertThatExceptionOfType(EntityExistsException.class).isThrownBy(() -> {
personInsertRepository.insertWithEntityManager(new Person(1L, "firstname", "lastname"));
personInsertRepository.insertWithEntityManager(new Person(1L, "firstname", "lastname"));
});
}
ネイティブクエリを使用するのとは対照的に、列名と対応する値を指定する必要はありません。 代わりに、EntityManagerがそれを処理します。
上記のテストでは、persistによってより特殊化されてスローされるスーパークラスPersistenceExceptionの代わりに、EntityExistsExceptionがスローされることも期待されます。
一方、この例では、次のことを確認する必要があります
6. 結論
この記事では、JPAオブジェクトに対して挿入操作を実行する方法を説明しました。 ネイティブクエリの使用例と、 EntityManager#persistを使用してカスタムINSERTステートメントを作成する例を確認しました。
いつものように、この記事で使用されている完全なコードは、GitHubでから入手できます。