Spring JPA @Query với LIKE


93

Tôi đang cố gắng tạo một phương thức trong CrudRepository có thể cung cấp cho tôi danh sách người dùng, có tên người dùng giống như tham số đầu vào (không chỉ bắt đầu bằng mà còn chứa nó). Tôi đã cố gắng sử dụng phương thức "findUserByUsernameLike(@Param("username") String username)"nhưng như nó được nói trong tài liệu Spring, phương thức này bằng " where user.username like ?1". Điều đó không tốt cho tôi, vì tôi đã nói rằng tôi đang cố lấy tất cả người dùng có tên người dùng chứa ...

Tôi đã viết một truy vấn cho phương thức nhưng nó thậm chí không triển khai.

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

Ai có thể giúp tôi với điều này?


4
Bạn có thể muốn sử dụng containingđể lợi ích từ các chỉ số, xem docs.spring.io/spring-data/jpa/docs/1.4.3.RELEASE/reference/...

Câu trả lời:


170

Hãy thử sử dụng cách tiếp cận sau (nó phù hợp với tôi):

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

Lưu ý: Tên bảng trong JPQL phải bắt đầu bằng chữ in hoa.


10
hoặc WHERE UPPER(u.username) LIKE CONCAT('%',UPPER(:username),'%')để làm một case-insensitive tìm kiếm
Brad Mace

SQL-Injection sử dụng giải pháp của bạn có được không? (hỏi vì CONCAT)
ramden

@ramden tất cả các @Params đều được khử trùng, vì vậy không.
nurettin

Bạn chỉ có thể làm như: tên người dùng và sau đó .setParameter ("tên người dùng", "% foo%");
Matthew Daumen

cách đặt .setParameter ("tên người dùng", "% foo%"); @MatthewDaumen
xuezhongyu01

120

Sử dụng tính năng Tạo truy vấn từ tên phương thức , hãy kiểm tra bảng 4 nơi chúng giải thích một số từ khóa.

  1. Sử dụng Like: select ... like: username

    List<User> findByUsernameLike(String username);
  2. StartWith: chọn ... như: tên người dùng%

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

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

    List<User> findByUsernameContaining(String username);

Lưu ý rằng câu trả lời mà bạn đang tìm kiếm là số 4 . Bạn không cần phải sử dụng @Query


Điều đó thực sự hữu ích, nhưng nếu tôi muốn sử dụng từ khóa Chứa, tôi có thể phân biệt chữ hoa chữ thường không? Trong tài liệu có điều gì đó nói về StringMatcher. Có vẻ như nếu tôi tạo một hàm riêng biệt với ExampleMatcher thì nó sẽ hoạt động, nhưng bằng cách nào đó tôi có thể khai báo nó trong tên phương thức không để viết hàm của riêng tôi chỉ để thêm phân biệt chữ hoa chữ thường này không?
V. Samma

11
Chỉ muốn thêm rằng bạn cũng có thể bỏ qua trường hợp, nếu cần thiết, như thế này: List<User> findByUsernameContainingIgnoreCase(String username);
Robert

Biểu tượng phần trăm nên được đảo ngược StartingWith: select ... like :username%EndingWith: select ... like %:username... dù sao câu trả lời tuyệt vời ... phải là câu trả lời được chấp nhận. Cảm ơn.
Alessandro

@Robert tôi có dữ liệu cột với chữ hoa và tôi đã sử dụng phương pháp JPQL like và truyền giá trị chữ thường và có thể nhận các giá trị. mà không có lờ đi, nó cũng đang tìm nạp dữ liệu trường hợp không phù hợp. Tại sao hành vi kỳ lạ này lại xảy ra?
greenhorn

@greenhorn Vui lòng mở một câu hỏi StackOverflow riêng biệt và thêm một số ví dụ về dữ liệu của bạn trong bảng và những gì bạn đang truy vấn.
Robert

25

Một cách khác: thay vào đó CONCAThàm chúng ta có thể sử dụng dấu ngoặc kép :: lastname || '%'

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

Bạn có thể đặt bất cứ đâu, tiền tố, hậu tố hoặc cả hai

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

10

List<User> findByUsernameContainingIgnoreCase(String username);

để bỏ qua các vấn đề trường hợp


SQL-Injection sử dụng giải pháp của bạn có được không?
xuezhongyu01 30/09/19


8

Đối với trường hợp của bạn, bạn có thể sử dụng trực tiếp các phương pháp JPA. Điều đó giống như dưới đây:

Chứa: select ... like%: username%

List<User> findByUsernameContainingIgnoreCase(String username);

ở đây, ignoreCase sẽ giúp bạn tìm kiếm mục mà bỏ qua trường hợp.

Dưới đây là một số phương pháp liên quan:

  1. Giống findByFirstnameLike

    … Nơi x.firstname như thế nào? 1

  2. Bắt đầu với findByFirstnameStartingWith

    … Trong đó x.firstname như? 1 (tham số liên kết với% được nối thêm)

  3. Kết thúc với findByFirstnameEndingWith

    … Trong đó x.firstname như thế nào? 1 (tham số liên kết với% được thêm vào trước)

  4. Chứa đựng findByFirstnameContaining

    … Trong đó x.firstname như? 1 (tham số được ràng buộc trong%)

Thông tin thêm, xem liên kết nàyliên kết này

Hy vọng điều này sẽ giúp bạn :)


Cảm ơn! Sử dụng các quy ước JPA có vẻ như là một cách đúng đắn.
FigletNewton

3

Cách này phù hợp với tôi, (sử dụng Spring Boot phiên bản 2.0.1. RELEASE):

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

Giải thích: Dấu? 1,? 2,? 3, v.v. là các trình giữ chỗ cho các tham số đầu tiên, thứ hai, thứ ba, v.v. Trong trường hợp này là đủ để tham số được bao quanh bởi% như thể nó là một truy vấn SQL chuẩn nhưng không có dấu nháy đơn.


bạn nên thích các thông số được đặt tên thay vì các số:@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);

Cảm ơn, vấn đề của việc giảm tải là jpql phân biệt chữ hoa chữ thường, bây giờ nó đang được triển khai, nhưng 'LIKE' không hoạt động như tôi muốn. Nó chỉ tìm các bản ghi hoàn toàn bằng với tham số đầu vào (không chứa nó).
Viktoriia

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

Tôi đã thử mã này và nó hoạt động.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.