«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. Заключение