«1. Введение

Spring Data JPA позволяет нам определять производные методы, которые читают, обновляют или удаляют записи из базы данных. Это очень полезно, поскольку сокращает шаблонный код уровня доступа к данным.

В этом руководстве мы сосредоточимся на определении и использовании методов удаления, производных от Spring Data, с практическими примерами кода.

2. Производные методы deleteBy

Во-первых, давайте настроим наш пример. Мы определим объект Fruit для сохранения имени и цвета элементов, доступных в магазине фруктов:

@Entity
public class Fruit {
    @Id
    private long id;
    private String name;
    private String color;
    // standard getters and setters
}

Затем мы добавим наш репозиторий для работы с объектами Fruit, расширив интерфейс JpaRepository и добавив наш производный методы этого класса.

Производные методы могут быть определены как ГЛАГОЛ + атрибут, определенный в сущности. Некоторые из разрешенных глаголов — это findBy, deleteBy и removeBy.

Давайте создадим метод для удаления Fruits по их имени:

@Repository
public interface FruitRepository extends JpaRepository<Fruit, Long> {
    Long deleteByName(String name);
}

В этом примере метод deleteByName возвращает количество удаленных записей.

Точно так же мы можем вывести метод удаления в следующем виде:

List<Fruit> deleteByColor(String color);

Здесь метод deleteByColor удаляет все фрукты заданного цвета и возвращает список удаленных записей.

Давайте протестируем производные методы удаления. Сначала мы добавим несколько записей в таблицу Fruit, определив данные в test-fruit-data.sql:

insert into fruit(id,name,color) values (1,'apple','red');
insert into fruit(id,name,color) values (2,'custard apple','green');
insert into fruit(id,name,color) values (3,'mango','yellow');
insert into fruit(id,name,color) values (4,'guava','green');

Затем удалим все «зеленые» фрукты:

@Transactional
@Test
@Sql(scripts = { "/test-fruit-data.sql" })
public void givenFruits_WhenDeletedByColor_ThenDeletedFruitsShouldReturn() {
     List<Fruit> fruits = fruitRepository.deleteByColor("green");

     assertEquals("number of fruits are not matching", 2, fruits.size());
     fruits.forEach(fruit -> assertEquals("It's not a green fruit", "green", fruit.getColor()));
}

~ ~~ Также обратите внимание, что нам нужно использовать аннотацию @Transactional для методов удаления.

Далее добавим аналогичный тестовый пример для второго метода deleteBy:

@Transactional
@Test
@Sql(scripts = { "/test-fruit-data.sql" })
public void givenFruits_WhenDeletedByName_ThenDeletedFruitCountShouldReturn() {

    Long deletedFruitCount = fruitRepository.deleteByName("apple");

    assertEquals("deleted fruit count is not matching", 1, deletedFruitCount.intValue());
}

3. Производные методы removeBy

Мы также можем использовать глагол removeBy для получения методов удаления:

Long removeByName(String name);
List<Fruit> removeByColor(String color);

Примечание. что нет никакой разницы в поведении двух типов методов.

Конечный интерфейс будет выглядеть так:

@Repository
public interface FruitRepository extends JpaRepository<Fruit, Long> {

    Long deleteByName(String name);

    List<Fruit> deleteByColor(String color);

    Long removeByName(String name);

    List<Fruit> removeByColor(String color);
}

Добавим аналогичные модульные тесты для методов removeBy:

@Transactional
@Test
@Sql(scripts = { "/test-fruit-data.sql" })
public void givenFruits_WhenRemovedByColor_ThenDeletedFruitsShouldReturn() {
    List<Fruit> fruits = fruitRepository.removeByColor("green");

    assertEquals("number of fruits are not matching", 2, fruits.size());
}
@Transactional
@Test
@Sql(scripts = { "/test-fruit-data.sql" })
public void givenFruits_WhenRemovedByName_ThenDeletedFruitCountShouldReturn() {
    Long deletedFruitCount = fruitRepository.removeByName("apple");

    assertEquals("deleted fruit count is not matching", 1, deletedFruitCount.intValue());
}

4. Производные удаленные методы против @Query

Мы можем встретить сценарий, который делает имя производного метода слишком большим или включает SQL JOIN между несвязанными сущностями.

В этом случае мы также можем использовать аннотации @Query и @Modifying для реализации операций удаления.

@Modifying
@Query("delete from Fruit f where f.name=:name or f.color=:color")
List<int> deleteFruits(@Param("name") String name, @Param("color") String color);

Давайте посмотрим на эквивалентный код для наших производных методов удаления, используя пользовательский запрос:

Хотя эти два решения кажутся похожими и дают один и тот же результат, они используют немного другой подход. Метод @Query создает один запрос JPQL к базе данных. Для сравнения, методы deleteBy выполняют запрос на чтение, а затем удаляют каждый из элементов один за другим.

Также метод deleteBy может возвращать список удаленных записей, а пользовательский запрос возвращает количество удаленных записей.

5. Заключение