Wiosna JPA @Query z LIKE

95

Próbuję stworzyć metodę w CrudRepository, która będzie w stanie podać mi listę użytkowników, których nazwy użytkowników są TAKIE JAK parametr wejściowy (nie tylko zaczynają się, ale również zawierają). Próbowałem użyć metody, "findUserByUsernameLike(@Param("username") String username)"ale jak jest powiedziane w dokumentacji Spring, ta metoda jest równa " where user.username like ?1". Nie jest to dla mnie dobre, ponieważ już powiedziałem, że próbuję zdobyć wszystkich użytkowników, których nazwa użytkownika zawiera ...

Napisałem zapytanie do metody, ale ona nawet się nie wdraża.

@Repository
public interface UserRepository extends CrudRepository<User, Long> {

@Query("select u from user u where u.username like '%username%'")
List<User> findUserByUsernameLike(@Param("username") String username);
}

Czy ktoś może mi w tym pomóc?

Viktoriia
źródło
4
Możesz chcieć użyć containing, aby skorzystać z indeksów, patrz docs.spring.io/spring-data/jpa/docs/1.4.3.RELEASE/reference/…

Odpowiedzi:

173

Spróbuj zastosować następujące podejście (u mnie działa):

@Query("SELECT u.username FROM User u WHERE u.username LIKE CONCAT('%',:username,'%')")
List<String> findUsersWithPartOfName(@Param("username") String username);

Uwaga: nazwa tabeli w JPQL musi zaczynać się wielką literą.

znak
źródło
11
lub WHERE UPPER(u.username) LIKE CONCAT('%',UPPER(:username),'%')do wyszukiwania bez rozróżniania wielkości liter
Brad Mace
Możliwe SQL-Injection przy użyciu Twojego rozwiązania? (pytając z powodu CONCAT)
ramden
@ramden wszystkie @Paramsą odkażone, więc nie.
nurettin
Możesz po prostu zrobić: nazwa użytkownika, a następnie .setParameter ("nazwa użytkownika", "% foo%");
Matthew Daumen
jak ustawić .setParameter ("nazwa użytkownika", "% foo%"); @MatthewDaumen
xuezhongyu01
122

Używając tworzenia zapytań na podstawie nazw metod , sprawdź tabelę 4, w której objaśniono niektóre słowa kluczowe.

  1. Korzystanie z Like: select ... like :username

     List<User> findByUsernameLike(String username);
    
  2. Począwszy od: select ... like :username%

     List<User> findByUsernameStartingWith(String username);
    
  3. Kończące się: select ... like %:username

     List<User> findByUsernameEndingWith(String username);
    
  4. Zawierający: select ... like %:username%

     List<User> findByUsernameContaining(String username);
    

Zwróć uwagę, że odpowiedź, której szukasz, to numer 4 . Nie musisz używać @Query

jmgoyesc
źródło
To bardzo pomocne, ale jeśli chcę użyć słowa kluczowego Containing, czy mogę również ustawić bez rozróżniania wielkości liter? W dokumentacji jest coś powiedziane o StringMatcherze. Wygląda na to, że gdybym utworzył oddzielną funkcję za pomocą ExampleMatchera, zadziałałaby, ale czy mogę w jakiś sposób zadeklarować ją w nazwie metody, aby nie pisać własnej funkcji tylko po to, aby dodać tę niewrażliwość na wielkość liter?
V. Samma
11
Chciałem tylko dodać, że w razie potrzeby możesz również zignorować przypadek, na przykład: List<User> findByUsernameContainingIgnoreCase(String username);
Robert
Symbol procentu powinien być odwrócony StartingWith: select ... like :username%i EndingWith: select ... like %:username... w każdym razie świetna odpowiedź ... powinna być akceptowana. Dzięki.
Alessandro
@Robert Mam dane w kolumnie z dużymi literami i użyłem metody podobnej do JPQL i przekazałem wartość małych liter i mogłem uzyskać wartości. bez IgnoreCase również pobiera nieprawidłowe dane przypadków. Dlaczego zdarzyło się to dziwne zachowanie?
nowicjusz
@greenhorn Otwórz osobne pytanie StackOverflow i dodaj przykład swoich danych w tabeli oraz to, o co prosisz.
Robert
25

Inny sposób: zamiast CONCATfunkcji możemy użyć podwójnej kreski:: lastname || „%”

@Query("select c from Customer c where c.lastName LIKE :lastname||'%'")
List<Customer> findCustomByLastName( @Param("lastname") String lastName);

Możesz wstawić dowolne miejsce, prefiks, sufiks lub oba

:lastname ||'%'  
'%' || :lastname  
'%' || :lastname || '%'  
remat_br
źródło
10

List<User> findByUsernameContainingIgnoreCase(String username);

aby zignorować problemy ze sprawami

Yusuf
źródło
Możliwe SQL-Injection przy użyciu Twojego rozwiązania?
xuezhongyu01
9

W twoim przypadku możesz bezpośrednio użyć metod JPA. To jest jak poniżej:

Zawiera: wybierz ... jak%: nazwa użytkownika%

List<User> findByUsernameContainingIgnoreCase(String username);

tutaj IgnoreCase pomoże ci wyszukać element z ignorowaniem przypadku.

Oto kilka powiązanych metod:

  1. Lubić findByFirstnameLike

    … Gdzie x.firstname jak? 1

  2. Zaczynając od findByFirstnameStartingWith

    … Gdzie x.firstname jak? 1 (parametr powiązany z dołączonym%)

  3. EndingWith findByFirstnameEndingWith

    … Gdzie x.firstname jak? 1 (parametr powiązany z przedrostkiem%)

  4. Zawierający findByFirstnameContaining

    … Gdzie x.firstname jak? 1 (parametr powiązany z%)

Więcej informacji, zobacz ten link i ten link

Mam nadzieję, że to ci pomoże :)

Md. Sajedul Karim
źródło
1
Dzięki! Używanie konwencji JPA wydaje się być właściwym sposobem.
FigletNewton
3

Ten sposób działa dla mnie (używając Spring Boot w wersji 2.0.1. RELEASE):

@Query("SELECT u.username FROM User u WHERE u.username LIKE %?1%")
List<String> findUsersWithPartOfName(@Param("username") String username);

Wyjaśnienie:? 1,? 2,? 3 itd. To symbole zastępcze pierwszego, drugiego, trzeciego parametru itd. W tym przypadku wystarczy, aby parametr był otoczony przez%, tak jakby to było standardowe zapytanie SQL, ale bez pojedyncze cytaty.

Uisleandro
źródło
1
powinieneś preferować wymienione parametry zamiast liczb:@Query("SELECT u.username FROM User u WHERE u.username LIKE %:username%")
Ralph
0
@Query("select u from user u where u.username LIKE :username")
List<User> findUserByUsernameLike(@Param("username") String username);
Mannekenpix
źródło
Dzięki, problem z deplouowaniem polegał na tym, że jpql rozróżnia wielkość liter, teraz jest wdrażany, ale „LIKE” nie działa tak, jak chcę. Znajduje tylko rekordy, które są całkowicie równe parametrowi wejściowemu (nie zawierają go).
Viktoriia
-1
@Query("select b.equipSealRegisterId from EquipSealRegister b where b.sealName like %?1% and b.deleteFlag = '0'" )
    List<String>findBySeal(String sealname);

Wypróbowałem ten kod i działa.

derrick.yang
źródło