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 .