SpringDataJPAの削除と関係
1. 概要
このチュートリアルでは、 Spring DataJPAで削除がどのように行われるかを見ていきます。
2. サンプルエンティティ
Spring Data JPAリファレンスドキュメントからわかるように、リポジトリインターフェイスはエンティティの基本的なサポートを提供します。
Bookなどのエンティティがあるとします。
@Entity
public class Book {
@Id
@GeneratedValue
private Long id;
private String title;
// standard constructors
// standard getters and setters
}
次に、Spring DataJPAのCrudRepository を拡張して、BookでのCRUD操作にアクセスできるようにします。
@Repository
public interface BookRepository extends CrudRepository<Book, Long> {}
3. リポジトリから削除
特に、 CrudRepository には、deleteByIdとdeleteAllの2つのメソッドが含まれています。
BookRepositoryから直接これらのメソッドをテストしてみましょう。
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Application.class})
public class DeleteFromRepositoryUnitTest {
@Autowired
private BookRepository repository;
Book book1;
Book book2;
List<Book> books;
// data initialization
@Test
public void whenDeleteByIdFromRepository_thenDeletingShouldBeSuccessful() {
repository.deleteById(book1.getId());
assertThat(repository.count()).isEqualTo(1);
}
@Test
public void whenDeleteAllFromRepository_thenRepositoryShouldBeEmpty() {
repository.deleteAll();
assertThat(repository.count()).isEqualTo(0);
}
}
また、 CrudRepository を使用している場合でも、JpaRepositoryやPagingAndSortingRepositoryなどの他のSpringDataJPAインターフェースにも同じメソッドが存在することに注意してください。
4. 派生削除クエリ
エンティティを削除するためのクエリメソッドを導出することもできます。 それらを書くための一連のルールがありますが、最も単純な例に焦点を当てましょう。
派生削除クエリはdeleteByで始まり、その後に選択基準の名前が続く必要があります。これらの基準はメソッド呼び出しで提供する必要があります。
titleでBookを削除したいとします。 命名規則を使用して、 deleteBy から始め、基準としてtitleをリストします。
@Repository
public interface BookRepository extends CrudRepository<Book, Long> {
long deleteByTitle(String title);
}
タイプlongの戻り値は、メソッドが削除したレコードの数を示します。
テストを書いて、それが正しいことを確認しましょう。
@Test
@Transactional
public void whenDeleteFromDerivedQuery_thenDeletingShouldBeSuccessful() {
long deletedRecords = repository.deleteByTitle("The Hobbit");
assertThat(deletedRecords).isEqualTo(1);
}
5. カスタム削除クエリ
派生クエリのメソッド名は非常に長くなる可能性があり、1つのテーブルに制限されます。
より複雑なものが必要な場合は、@Queryと@Modifyingを一緒に使用してカスタムクエリを作成できます。
以前の派生メソッドの同等のコードを確認してみましょう。
@Modifying
@Query("delete from Book b where b.title=:title")
void deleteBooks(@Param("title") String title);
繰り返しますが、簡単なテストで動作することを確認できます。
@Test
@Transactional
public void whenDeleteFromCustomQuery_thenDeletingShouldBeSuccessful() {
repository.deleteBooks("The Hobbit");
assertThat(repository.count()).isEqualTo(1);
}
上記の両方のソリューションは類似しており、同じ結果を達成します。 ただし、アプローチは少し異なります。
@Query メソッドは、データベースに対して単一のJPQLクエリを作成します。 比較すると、 deleteBy メソッドは読み取りクエリを実行してから、各アイテムを1つずつ削除します。
6. リレーションシップで削除
さて、私たちが持っているときに何が起こるか見てみましょう
OneToManyとBookエンティティが関連付けられているCategoryエンティティがあるとします。
@Entity
public class Category {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "category", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Book> books;
// standard constructors
// standard getters and setters
}
CategoryRepository は、CrudRepositoryを拡張する空のインターフェイスにすることができます。
@Repository
public interface CategoryRepository extends CrudRepository<Category, Long> {}
また、この関連付けを反映するようにBookエンティティを変更する必要があります。
@ManyToOne
private Category category;
次に、2つのカテゴリを追加して、現在所有している本に関連付けます。
カテゴリを削除しようとすると、書籍も削除されます:
@Test
public void whenDeletingCategories_thenBooksShouldAlsoBeDeleted() {
categoryRepository.deleteAll();
assertThat(bookRepository.count()).isEqualTo(0);
assertThat(categoryRepository.count()).isEqualTo(0);
}
これは双方向ではありませんが、つまり、本を削除しても、カテゴリは引き続き存在します。
@Test
public void whenDeletingBooks_thenCategoriesShouldAlsoBeDeleted() {
bookRepository.deleteAll();
assertThat(bookRepository.count()).isEqualTo(0);
assertThat(categoryRepository.count()).isEqualTo(2);
}
CascadeType などの関係のプロパティを変更することで、この動作を変更できます。
7. 結論
この記事では、SpringDataJPAでエンティティを削除するさまざまな方法を見てきました。
CrudRepository から提供された削除メソッドと、@Queryアノテーションを使用した派生クエリまたはカスタムメソッドを確認しました。
また、リレーションシップで削除がどのように行われるかを見ました。
いつものように、この記事で言及されているすべてのコードスニペットは、GitHubリポジトリにあります。