Spring Data: obsługiwane jest „usuwanie przez”?

100

Używam Spring JPA do dostępu do bazy danych. Potrafię znaleźć przykłady takie jak findByName i countByName, dla których nie muszę pisać żadnej implementacji metody. Mam nadzieję, że znajdę przykłady usunięcia grupy rekordów na podstawie jakiegoś warunku.

Czy Spring JPA obsługuje usuwanie typu deleteByName? Każdy wskaźnik jest doceniany.

Pozdrawiam i dziękuję.

ciekawy 1
źródło

Odpowiedzi:

185

Nieaktualna odpowiedź (Spring Data JPA <= 1.6.x) :

@Modifyingadnotacja na ratunek. Musisz jednak podać własne zachowanie SQL.

public interface UserRepository extends JpaRepository<User, Long> {
    @Modifying
    @Query("delete from User u where u.firstName = ?1")
    void deleteUsersByFirstName(String firstName);
}

Aktualizacja:

W nowoczesnych wersji wiosennej Danych JPA (> = 1.7.x) Zapytanie o wyprowadzeniu dla delete, removei countoperacji jest dostępny.

public interface UserRepository extends CrudRepository<User, Long> {

    Long countByFirstName(String firstName);

    Long deleteByFirstName(String firstName);

    List<User> removeByFirstName(String firstName);

}
Andrey Atapin
źródło
2
@AndreyAtapin Downvote, ponieważ nie jest to już dobra odpowiedź. Może to usunąć? Jedną z luk w przepływie stosu jest obsługa zmian wersji / poprawek błędów związanych z przedmiotowymi bibliotekami.
Ben George,
1
@webgeek, rozwiązałem ten problem za pomocą DELETE FROM x WHERE id = ?1 or parent_id = ?1. Przy okazji, upewnij się, że nie masz typu parent__id(czy celowo masz podwójny niski myślnik?). Dlaczego jednak używasz natywnej opcji zapytania?
Andrey Atapin
4
Nawet ja używam wersji 1.7.4, potrzebna jest adnotacja @Transactional powyżej metody zapytania, aby pomyślnie
usunąć
40
Zwykle w aplikacji będziesz mieć klasy / metody @ Service, które będą wywoływały repozytoria. Metody publiczne @ Service powinny być metodami oznaczonymi jako @ Transactional, ponieważ transakcje są oparte na przypadku użycia. Oznacza to, że przypadek użycia musi zostać w pełni zatwierdzony lub wycofany. Nie każda metoda repozytorium. Więc PROSZĘ NIE używaj @ Transactional na metodach repozytorium. Ale w metodach usługi, które używają repozytorium.
user1567291
1
Dokonywanie @Transactional w repo oznacza wewnątrz usługi, jeśli wywołujesz repo wiele razy, każdy z nich będzie miał transakcję diff, więc wycofaj w ciągu 1 zapytania. Jeśli zapewniasz na poziomie usług, cała Twoja funkcja zostanie wycofana po każdym błędzie.
P Satish Patro
78

Wyprowadzanie zapytań usuwających przy użyciu podanej nazwy metody jest obsługiwane począwszy od wersji 1.6.0.RC1 Spring Data JPA. Słowa kluczowe removei deletesą obsługiwane. Jako wartość zwracaną można wybrać liczbę lub listę usuniętych jednostek.

Long removeByLastname(String lastname);

List<User> deleteByLastname(String lastname);
Christoph Strobl
źródło
7

Jeśli spojrzysz na kod źródłowy Spring Data JPA, a szczególnie na PartTreeJpaQueryklasę, zobaczysz, że próbuje on utworzyć instancję PartTree. Wewnątrz tej klasy następujące wyrażenie regularne

private static final Pattern PREFIX_TEMPLATE = Pattern.compile("^(find|read|get|count|query)(\\p{Lu}.*?)??By")

powinien wskazywać, co jest dozwolone, a co nie.

Oczywiście, jeśli spróbujesz dodać taką metodę, zobaczysz, że to nie działa i otrzymasz pełny ślad stosu.

Powinienem zauważyć, że korzystałem z wersji 1.5.0.RELEASESpring Data JPA

geoand
źródło
6

2 drogi:-

Pierwsze zapytanie niestandardowe

@Modifying
@Query("delete from User where firstName = :firstName")
void deleteUsersByFirstName(@Param("firstName") String firstName);

2. jedno zapytanie JPA według metody

List<User> deleteByLastname(String lastname);

Kiedy przejdziesz z zapytaniem metodą (drugi sposób), najpierw wykona wywołanie get

select * from user where last_name = :firstName

Następnie załaduje go na listę, a następnie wywoła delete id jeden po drugim

delete from user where id = 18
delete from user where id = 19

Najpierw pobierz listę obiektów, a potem pętla do usuwania identyfikatorów jeden po drugim

Ale pierwsza opcja (zapytanie niestandardowe),

To tylko jedno zapytanie. Zostanie usunięte wszędzie tam, gdzie istnieje wartość.

Przejdź również przez ten link https://www.baeldung.com/spring-data-jpa-deleteby

P Satish Patro
źródło
1
Dzięki za informację!
ciekawy 1
2

Jeśli użyjesz predefiniowanych metod usuwania, które są bezpośrednio dostarczane przez Spring JPA, wówczas poniższe dwa zapytania zostaną wykonane przez framework.

  • Najpierw zbierz dane (takie jak id i inne kolumny), używając przez wykonanie zapytania wybierającego z klauzulą ​​delete query where.

  • następnie po uzyskaniu wyniku Zestaw pierwszego zapytania, drugie zapytania usuwające zostaną wykonane dla wszystkich identyfikatorów (jeden po drugim)

    Uwaga: nie jest to zoptymalizowany sposób dla twojej aplikacji, ponieważ wiele zapytań zostanie wykonanych dla pojedynczego zapytania usuwającego MYSQL.

Jest to kolejny zoptymalizowany sposób usuwania kodu zapytania, ponieważ tylko jedno zapytanie usuwające zostanie wykonane przy użyciu poniższych metod niestandardowych.



@NamedNativeQueries({

@NamedNativeQuery(name = "Abc.deleteByCreatedTimeBetween",
            query = "DELETE FROM abc WHERE create_time BETWEEN ?1 AND ?2")
    ,

    @NamedNativeQuery(name = "Abc.getByMaxId",
            query = "SELECT max(id) from abc")
})

@Entity
public class Abc implements Serializable {

}

@Repository
public interface AbcRepository extends CrudRepository {

    int getByMaxId();

    @Transactional
    @Modifying
    void deleteByCreatedTimeBetween(String startDate, String endDate);
}

Suneet Khurana
źródło
1

Zachowaj ostrożność podczas używania zapytania pochodnego do usuwania wsadowego. To nie jest to, czego oczekujesz: DeleteExecution

Andrey Ofim
źródło
Cześć. Jeśli zwracasz uwagę na RBAR (wiersz przez bolesny wiersz), czy możesz dodać to do swojej odpowiedzi? (i zagłosuję za). Domyślam się, co tu wskazujesz.
granadaCoder
0

Tak, metoda deleteBy jest obsługiwana.Aby jej użyć, należy oznaczyć metodę adnotacją @Transactional

amoljdv06
źródło