Spring JPA @Query dengan LIKE


95

Saya mencoba membuat metode di CrudRepository yang akan dapat memberi saya daftar pengguna, yang nama penggunanya LIKE parameter input (tidak hanya dimulai dengan, tetapi juga mengandungnya). Saya mencoba menggunakan metode "findUserByUsernameLike(@Param("username") String username)"tetapi seperti yang diceritakan dalam dokumentasi Spring, metode ini sama dengan " where user.username like ?1". Ini tidak baik untuk saya, karena saya sudah memberi tahu bahwa saya mencoba mendapatkan semua pengguna yang nama penggunanya berisi ...

Saya menulis kueri ke metode tetapi bahkan tidak menyebarkan.

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

Adakah yang bisa membantu saya dengan ini?


4
Anda mungkin ingin menggunakan containinguntuk mendapatkan keuntungan dari indeks, lihat docs.spring.io/spring-data/jpa/docs/1.4.3.RELEASE/reference/…

Jawaban:


173

Coba gunakan pendekatan berikut (ini berhasil untuk saya):

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

Perhatian: Nama tabel dalam JPQL harus dimulai dengan huruf kapital.


11
atau WHERE UPPER(u.username) LIKE CONCAT('%',UPPER(:username),'%')untuk melakukan pencarian tidak peka huruf besar / kecil
Brad Mace

SQL-Injection menggunakan solusi Anda mungkin? (bertanya karena CONCAT)
ramden

@ramden semua @Paramsudah dibersihkan, jadi tidak.
nurettin

Anda bisa melakukan seperti: username dan kemudian .setParameter ("username", "% foo%");
Matthew Daumen

cara menyetel .setParameter ("username", "% foo%"); @MatthewDaumen
xuezhongyu01

122

Menggunakan pembuatan Query dari nama metode , periksa tabel 4 di mana mereka menjelaskan beberapa kata kunci.

  1. Menggunakan Suka: select ... like :username

     List<User> findByUsernameLike(String username);
    
  2. Dimulai dengan: select ... like :username%

     List<User> findByUsernameStartingWith(String username);
    
  3. EndingWith: select ... like %:username

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

     List<User> findByUsernameContaining(String username);
    

Perhatikan bahwa jawaban yang Anda cari adalah angka 4 . Anda tidak harus menggunakan @Query


Itu sangat membantu, tetapi jika saya ingin menggunakan kata kunci Mengandung, dapatkah saya juga membuatnya peka huruf besar kecil? Dalam dokumentasi ada sesuatu yang dikatakan tentang StringMatcher. Tampaknya jika saya membuat fungsi terpisah dengan ExampleMatcher, ini akan berfungsi, tetapi dapatkah saya mendeklarasikannya dalam nama metode agar tidak menulis fungsi saya sendiri hanya untuk menambahkan ketidaksensitifan huruf ini?
V. Samma

11
Hanya ingin menambahkan bahwa Anda juga dapat mengabaikan kasus, jika perlu, seperti ini: List<User> findByUsernameContainingIgnoreCase(String username);
Robert

Simbol persen harus dibalik StartingWith: select ... like :username%dan EndingWith: select ... like %:username... bagaimanapun juga jawaban yang bagus ... harus yang diterima. Terima kasih.
Alessandro

@Robert saya memiliki data kolom dengan huruf besar dan saya menggunakan metode seperti JPQL dan melewati nilai huruf kecil dan bisa mendapatkan nilai. tanpa IgnoreCase juga mengambil data kasus yang tidak tepat. Mengapa perilaku aneh ini terjadi?
penghijauan

@greenhorn Harap buka pertanyaan StackOverflow terpisah dan tambahkan beberapa contoh data Anda di tabel dan apa yang Anda minta.
Robert

25

Cara lain: sebagai gantinya CONCATfungsi kita bisa menggunakan pipa ganda :: lastname || '%'

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

Anda bisa meletakkan di mana saja, awalan, sufiks atau keduanya

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

10

List<User> findByUsernameContainingIgnoreCase(String username);

untuk mengabaikan masalah kasus


SQL-Injection menggunakan solusi Anda mungkin?
xuezhongyu01

9

Untuk kasus Anda, Anda dapat langsung menggunakan metode JPA. Itu seperti di bawah ini:

Berisi: pilih ... like%: username%

List<User> findByUsernameContainingIgnoreCase(String username);

Di sini, IgnoreCase akan membantu Anda mencari item dengan mengabaikan case.

Berikut beberapa metode terkait:

  1. Suka findByFirstnameLike

    … Di mana x.firstname seperti? 1

  2. Dimulai dengan findByFirstnameStartingWith

    … Di mana x.firstname seperti? 1 (parameter terikat dengan% tambahan)

  3. EndingWith findByFirstnameEndingWith

    … Di mana x.firstname seperti? 1 (parameter terikat dengan% diawali)

  4. Berisi findByFirstnameContaining

    … Di mana x.firstname seperti? 1 (parameter terikat dibungkus dalam%)

Info lebih lanjut, lihat link ini dan link ini

Semoga ini bisa membantu Anda :)


1
Terima kasih! Menggunakan konvensi JPA terasa seperti cara yang benar.
FigletNewton


3

Cara ini berfungsi untuk saya, (menggunakan Spring Boot versi 2.0.1. RELEASE):

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

Menjelaskan: The? 1,? 2,? 3 dll. Adalah placeholder parameter pertama, kedua, ketiga, dll. Dalam hal ini cukup memiliki parameter yang dikelilingi oleh% seolah-olah itu adalah kueri SQL standar tetapi tanpa tanda kutip tunggal.


1
Anda harus memilih parameter bernama daripada angka:@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);

Terima kasih, masalah deplouing adalah jpql case sensitive, sekarang sedang di-deploy, tetapi 'LIKE' tidak berfungsi seperti yang saya inginkan. Ia hanya menemukan record yang sama dengan parameter input sepenuhnya (tidak mengandungnya).
Viktoriia

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

Saya telah mencoba kode ini dan berhasil.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.