Spring JPA @Query พร้อม LIKE


95

ฉันกำลังพยายามสร้างเมธอดใน CrudRepository ที่จะสามารถให้รายชื่อผู้ใช้ที่มีชื่อผู้ใช้เป็นเหมือนพารามิเตอร์อินพุต (ไม่เพียง แต่เริ่มต้นด้วย แต่ยังมีอยู่ด้วย) ฉันพยายามใช้ method "findUserByUsernameLike(@Param("username") String username)"แต่ตามที่บอกไว้ในเอกสาร Spring เมธอดนี้เท่ากับ " where user.username like ?1" มันไม่ดีสำหรับฉันอย่างที่ฉันได้บอกไปแล้วว่าฉันพยายามดึงผู้ใช้ทั้งหมดที่มีชื่อผู้ใช้ ...

ฉันเขียนแบบสอบถามถึงวิธีการ แต่มันไม่ได้ปรับใช้

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

มีใครช่วยฉันได้ไหม


4
คุณอาจต้องการใช้containingเพื่อให้ได้ประโยชน์จากดัชนีโปรดดูdocs.spring.io/spring-data/jpa/docs/1.4.3.RELEASE/reference/…

คำตอบ:


173

ลองใช้แนวทางต่อไปนี้ (ใช้ได้กับฉัน):

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

หมายเหตุ: ชื่อตารางใน JPQL ต้องขึ้นต้นด้วยอักษรตัวใหญ่


11
หรือWHERE UPPER(u.username) LIKE CONCAT('%',UPPER(:username),'%')ทำการค้นหาแบบไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่
Brad Mace

SQL-Injection โดยใช้โซลูชันของคุณเป็นไปได้หรือไม่? (ถามเพราะ CONCAT)
ramden

@ramden ทั้งหมด@Paramถูกฆ่าเชื้อดังนั้นไม่
nurettin

คุณสามารถทำได้เช่น: ชื่อผู้ใช้และ. setParameter ("ชื่อผู้ใช้", "% foo%");
Matthew Daumen

วิธีตั้งค่า. setParameter ("username", "% foo%"); @MatthewDaumen
xuezhongyu01

122

ใช้การสร้าง Query จากชื่อวิธีการตรวจสอบตารางที่ 4 ซึ่งอธิบายคำหลักบางคำ

  1. ใช้ Like: select ... like :username

     List<User> findByUsernameLike(String username);
    
  2. เริ่มต้นด้วย: select ... like :username%

     List<User> findByUsernameStartingWith(String username);
    
  3. สิ้นสุดด้วย: select ... like %:username

     List<User> findByUsernameEndingWith(String username);
    
  4. บรรจุ: select ... like %:username%

     List<User> findByUsernameContaining(String username);
    

แจ้งให้ทราบว่าคำตอบที่คุณกำลังมองหาคือหมายเลข 4 คุณไม่จำเป็นต้องใช้ @Query


นั่นเป็นประโยชน์มาก แต่ถ้าฉันต้องการใช้คำหลักที่มีอยู่ฉันสามารถทำให้มันไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่ได้หรือไม่ ในเอกสารมีบางอย่างกล่าวเกี่ยวกับ StringMatcher ดูเหมือนว่าถ้าฉันสร้างฟังก์ชันแยกต่างหากกับ ExampleMatcher มันจะใช้งานได้ แต่ฉันจะประกาศในชื่อวิธีการไม่ให้เขียนฟังก์ชันของตัวเองเพียงเพื่อเพิ่มกรณี - ไม่ไวได้หรือไม่
V. สัมมา

11
แค่อยากจะเพิ่มว่าคุณสามารถละเว้นตัวพิมพ์เล็กและใหญ่ได้หากจำเป็นเช่นนี้: List<User> findByUsernameContainingIgnoreCase(String username);
Robert

สัญลักษณ์เปอร์เซ็นต์ควรกลับด้านStartingWith: select ... like :username%และEndingWith: select ... like %:username... อย่างไรก็ตามคำตอบที่ดี ... ควรเป็นคำตอบที่ยอมรับ ขอบคุณ.
Alessandro

@ Robert ฉันมีข้อมูลคอลัมน์ที่มีตัวพิมพ์ใหญ่และฉันใช้วิธี JPQL like และส่งผ่านค่าตัวพิมพ์เล็กและสามารถรับค่าได้ หากไม่มี IgnoreCase ก็กำลังดึงข้อมูลกรณีที่ไม่เหมาะสม ทำไมพฤติกรรมแปลก ๆ ถึงเกิดขึ้น?
greenhorn

@greenhorn โปรดเปิดคำถาม StackOverflow แยกต่างหากและเพิ่มตัวอย่างข้อมูลของคุณในตารางและสิ่งที่คุณกำลังค้นหา
Robert

25

อีกวิธีหนึ่ง: แทนCONCATฟังก์ชันเราสามารถใช้ท่อคู่: นามสกุล || '%'

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

คุณสามารถใส่ที่ใดก็ได้คำนำหน้าคำต่อท้ายหรือทั้งสองอย่าง

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

10

List<User> findByUsernameContainingIgnoreCase(String username);

เพื่อละเว้นปัญหากรณี


SQL-Injection โดยใช้โซลูชันของคุณเป็นไปได้หรือไม่?
xuezhongyu01

9

ใช้งานง่ายดังต่อไปนี้ (ไม่จำเป็นต้องใช้ CONCAT หรือ ||):

@Query("from Service s where s.category.typeAsString like :parent%")
List<Service> findAll(@Param("parent") String parent);

บันทึกไว้ใน: http://docs.spring.io/spring-data/jpa/docs/current/reference/html


9

สำหรับกรณีของคุณคุณสามารถใช้วิธี JPA ได้โดยตรง ที่เหมือนร้อง:

ประกอบด้วย: เลือก ... เช่น%: ชื่อผู้ใช้%

List<User> findByUsernameContainingIgnoreCase(String username);

ที่นี่IgnoreCaseจะช่วยให้คุณค้นหารายการโดยไม่สนใจกรณี

วิธีการที่เกี่ยวข้องมีดังนี้

  1. ชอบ findByFirstnameLike

    … x.firstname ชอบที่ไหน 1

  2. เริ่มต้นด้วย findByFirstnameStartingWith

    …โดยที่ x.firstname ชอบ 1 (พารามิเตอร์ที่ผูกกับ% ต่อท้าย)

  3. สิ้นสุดด้วย findByFirstnameEndingWith

    …โดยที่ x.firstname ต้องการ 1 (พารามิเตอร์ที่ผูกด้วย% ที่นำหน้า)

  4. ที่มี findByFirstnameContaining

    …โดยที่ x.firstname ต้องการ 1 (พารามิเตอร์ที่ถูกผูกไว้ใน%)

ข้อมูลเพิ่มเติมดูลิงค์นี้และลิงค์นี้

หวังว่านี่จะช่วยคุณได้ :)


1
ขอบคุณ! การใช้อนุสัญญา JPA เป็นวิธีที่ถูกต้อง
FigletNewton

3

วิธีนี้ใช้ได้ผลกับฉัน (โดยใช้ Spring Boot เวอร์ชัน 2.0.1 ปล่อย):

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

อธิบาย:? 1,? 2,? 3 ฯลฯ เป็นตัวยึดพารามิเตอร์ตัวแรกตัวที่สองตัวที่สามเป็นต้นในกรณีนี้ก็เพียงพอที่จะให้พารามิเตอร์ล้อมรอบด้วย% ราวกับว่าเป็นแบบสอบถาม SQL มาตรฐาน แต่ไม่มี คำพูดเดียว


1
คุณควรตั้งชื่อพารามิเตอร์แทนตัวเลข:@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);

ขอบคุณปัญหาของการลบล้างคือ jpql เป็นกรณีที่สำคัญตอนนี้กำลังปรับใช้ แต่ 'LIKE' ไม่ทำงานตามที่ฉันต้องการ พบเพียงระเบียนที่เท่ากับอินพุตพารามิเตอร์ทั้งหมด (ไม่ได้มี)
Viktoriia

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.