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 には、deleteByIddeleteAllの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 を使用している場合でも、JpaRepositoryPagingAndSortingRepositoryなどの他のSpringDataJPAインターフェースにも同じメソッドが存在することに注意してください。

4. 派生削除クエリ

エンティティを削除するためのクエリメソッドを導出することもできます。 それらを書くための一連のルールがありますが、最も単純な例に焦点を当てましょう。

派生削除クエリはdeleteByで始まり、その後に選択基準の名前が続く必要があります。これらの基準はメソッド呼び出しで提供する必要があります。

titleBookを削除したいとします。 命名規則を使用して、 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);
}

JPAでオブジェクトを永続化および削除するには、トランザクションが必要です。 そのため、これらの派生削除クエリを使用する場合は、@ Transactionalアノテーションを使用して、トランザクションが実行されていることを確認する必要があります。 これについては、 Springドキュメントを使用したORM

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. リレーションシップで削除

さて、私たちが持っているときに何が起こるか見てみましょう他のエンティティとの関係。

OneToManyBookエンティティが関連付けられている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リポジトリにあります。