Перейти к основному содержимому

Spring Data JPA — производные методы удаления

· 4 мин. чтения

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 .

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

@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. Вывод

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