Spring JPA @Query con LIKE


93

Sto cercando di creare un metodo in CrudRepository che sia in grado di fornirmi un elenco di utenti, i cui nomi utente sono COME il parametro di input (non solo inizia con, ma lo contiene anche). Ho provato a utilizzare il metodo "findUserByUsernameLike(@Param("username") String username)"ma, come viene detto nella documentazione di Spring, questo metodo è uguale a " where user.username like ?1". Non va bene per me, poiché ho già detto che sto cercando di ottenere tutti gli utenti il ​​cui nome utente contiene ...

Ho scritto una query sul metodo ma non viene nemmeno distribuito.

@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);
}

Qualcuno può aiutarmi con questo?


4
Potresti utilizzarlo containingper trarre vantaggio dagli indici, vedi docs.spring.io/spring-data/jpa/docs/1.4.3.RELEASE/reference/…

Risposte:


170

Prova a utilizzare il seguente approccio (funziona per me):

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

Avviso: il nome della tabella in JPQL deve iniziare con una lettera maiuscola.


10
o WHERE UPPER(u.username) LIKE CONCAT('%',UPPER(:username),'%')per fare una ricerca senza distinzione tra maiuscole e minuscole
Brad Mace,

SQL-Injection utilizzando la tua soluzione possibile? (chiedendo a causa di CONCAT)
ramden

@ramden tutti @Parami messaggi sono disinfettati, quindi no.
nurettin

Puoi semplicemente fare come: username e poi .setParameter ("username", "% foo%");
Matthew Daumen

come impostare .setParameter ("username", "% foo%"); @MatthewDaumen
xuezhongyu01

120

Utilizzando la creazione di query dai nomi dei metodi , controlla la tabella 4 dove spiegano alcune parole chiave.

  1. Utilizzando Mi piace: seleziona ... mi piace: nome utente

    List<User> findByUsernameLike(String username);
  2. Avvio con: seleziona ... come: nome utente%

    List<User> findByUsernameStartingWith(String username);
  3. EndingWith: seleziona ... come%: nomeutente

    List<User> findByUsernameEndingWith(String username);
  4. Contenente: seleziona ... come%: nome utente%

    List<User> findByUsernameContaining(String username);

Nota che la risposta che stai cercando è la numero 4 . Non è necessario utilizzare @Query


È davvero utile, ma se desidero utilizzare la parola chiave Containing, posso anche renderla senza distinzione tra maiuscole e minuscole? Nella documentazione c'è qualcosa detto su StringMatcher. Sembra che se creassi una funzione separata con ExampleMatcher funzionerebbe, ma posso in qualche modo dichiararlo nel nome del metodo per non scrivere la mia funzione solo per l'aggiunta di questa insensibilità al maiuscolo / minuscolo?
V. Samma

11
Volevo solo aggiungere che puoi anche ignorare le maiuscole / minuscole, se necessario, in questo modo: List<User> findByUsernameContainingIgnoreCase(String username);
Robert

Il simbolo della percentuale dovrebbe essere invertito StartingWith: select ... like :username%e EndingWith: select ... like %:username... comunque ottima risposta ... dovrebbe essere quella accettata. Grazie.
Alessandro

@ Robert ho una colonna di dati con lettere maiuscole e ho usato il metodo JPQL e ho passato un valore minuscolo e in grado di ottenere i valori. senza IgnoreCase sta anche recuperando i dati dei casi impropri. Perché si è verificato questo strano comportamento?
Greenhorn

@greenhorn Si prega di aprire una domanda StackOverflow separata e aggiungere alcuni esempi dei dati nella tabella e ciò per cui si sta eseguendo la query.
Robert

25

Un altro modo: al posto della CONCATfunzione possiamo usare double pipe :: lastname || '%'

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

Puoi mettere ovunque, prefisso, suffisso o entrambi

:lastname ||'%'  
'%' || :lastname  
'%' || :lastname || '%'  

10

List<User> findByUsernameContainingIgnoreCase(String username);

per ignorare i problemi del caso


SQL-Injection utilizzando la tua soluzione possibile?
xuezhongyu01


8

Per il tuo caso, puoi utilizzare direttamente i metodi JPA. Questo è come il muggito:

Contenente: seleziona ... come%: nome utente%

List<User> findByUsernameContainingIgnoreCase(String username);

qui, IgnoreCase ti aiuterà a cercare l'elemento ignorando il caso.

Ecco alcuni metodi correlati:

  1. Piace findByFirstnameLike

    ... dove x.firstname è simile? 1

  2. Iniziare con findByFirstnameStartingWith

    ... dove x.firstname come? 1 (parametro associato con% aggiunto)

  3. EndingWith findByFirstnameEndingWith

    ... dove x.firstname come? 1 (parametro associato con% anteposto)

  4. Contenente findByFirstnameContaining

    ... dove x.firstname è come? 1 (limite del parametro racchiuso in%)

Maggiori informazioni, visualizzare questo collegamento e questo collegamento

Spero che questo ti possa aiutare :)


Grazie! L'uso delle convenzioni JPA sembra il modo giusto.
FigletNewton

3

In questo modo funziona per me, (utilizzando Spring Boot versione 2.0.1. RELEASE):

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

Spiegazione:? 1,? 2,? 3 ecc.Sono segnaposto il primo, il secondo, il terzo parametro, ecc. In questo caso è sufficiente che il parametro sia circondato da% come se fosse una query SQL standard ma senza il virgolette singole.


dovresti preferire i parametri nominati invece dei numeri:@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);

Grazie, il problema della distribuzione era che jpql distingue tra maiuscole e minuscole, ora si sta distribuendo, ma "MI PIACE" non funziona come voglio. Trova solo i record che sono completamente uguali al parametro di input (non lo contengono).
Viktoriia

-1
@Query("select b.equipSealRegisterId from EquipSealRegister b where b.sealName like %?1% and b.deleteFlag = '0'" )
    List<String>findBySeal(String sealname);

Ho provato questo codice e funziona.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.