Весняний JPA @Query з LIKE


93

Я намагаюся створити метод у CrudRepository, який зможе дати мені список користувачів, чиї імена користувачів ПОДОБАЮТЬСЯ Вхідним параметром (не тільки починається з, але і містить його). Я намагався використати метод, "findUserByUsernameLike(@Param("username") String username)"але, як сказано у весняній документації, цей метод дорівнює " 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/…

Відповіді:


170

Спробуйте застосувати наступний підхід (він працює для мене):

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

Примітка: Назва таблиці в JPQL повинна починатися з великої літери.


10
або WHERE UPPER(u.username) LIKE CONCAT('%',UPPER(:username),'%')здійснити пошук без урахування регістру
Бред Мейс

Можлива SQL-ін'єкція за допомогою вашого рішення? (запитує через CONCAT)
протаранив

@ramden всі @Paramдезінфіковані, тому ні.
нуреттин

Ви можете просто зробити, як: ім'я користувача, а потім .setParameter ("ім'я користувача", "% foo%");
Метью Домен,

як встановити .setParameter ("ім'я користувача", "% foo%"); @MatthewDaumen
xuezhongyu01

120

Використовуючи створення запитів з імен методів , перевірте таблицю 4, де вони пояснюють деякі ключові слова.

  1. За допомогою Подобається: виберіть ... подобається: ім'я користувача

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

    List<User> findByUsernameStartingWith(String username);
  3. EndingWith: виберіть ... як%: ім'я користувача

    List<User> findByUsernameEndingWith(String username);
  4. Містить: select ... like%: username%

    List<User> findByUsernameContaining(String username);

Зверніть увагу, що відповідь, яку ви шукаєте, - номер 4 . Вам не потрібно використовувати @Query


Це дійсно корисно, але якщо я хочу використовувати ключове слово Contention, чи можу я також зробити його нечутливим до регістру? У документації є щось сказане про StringMatcher. Здається, якщо б я створив окрему функцію з ExampleMatcher, це спрацювало б, але чи можу я якось оголосити це в назві методу, щоб не писати власну функцію лише для додавання цієї чутливості до регістру?
V. Samma

11
Просто хотів додати, що ви також можете ігнорувати справи, якщо це потрібно, так: List<User> findByUsernameContainingIgnoreCase(String username);
Роберт

Символ відсотків повинен бути інвертованим StartingWith: select ... like :username%і EndingWith: select ... like %:username... у будь-якому випадку чудова відповідь ... повинна бути прийнятою. Дякую.
Алессандро

@ Роберт, у мене є дані стовпця з великими літерами, і я використав метод, подібний до JPQL, і передав значення з нижнього регістру і зміг отримати значення. без IgnoreCase також відбувається отримання даних про неналежні випадки. Чому трапляється така дивна поведінка?
greenhorn

@greenhorn Будь ласка, відкрийте окреме запитання StackOverflow і додайте в таблицю кілька прикладів своїх даних та того, що ви запитуєте.
Роберт

25

Інший спосіб: замість CONCATфункції ми можемо використовувати double pipe :: прізвище || '%'

@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-ін'єкція за допомогою вашого рішення?
xuezhongyu01


8

Для Вашого випадку Ви можете безпосередньо використовувати методи JPA. Це як нижче:

Містить: select ... like%: username%

List<User> findByUsernameContainingIgnoreCase(String username);

тут, IgnoreCase допоможе вам шукати елемент із ігноруванням справи.

Ось кілька пов’язаних методів:

  1. Подібно до findByFirstnameLike

    ... де x.ім'я як? 1

  2. Починаючи з findByFirstnameStartingWith

    ... де x.firstname подобається? 1 (параметр пов'язаний з доданим%)

  3. Закінчується findByFirstnameEndingWith

    ... де x.firstname подобається? 1 (параметр пов'язаний з доданим%)

  4. Містить findByFirstnameContaining

    … Де x.firstname на зразок? 1 (параметр пов’язаний загорнутим у%)

Більше інформації, перегляньте це посилання та це посилання

Сподіваюся, це допоможе вам :)


Дякую! Використання конвенцій JPA здається правильним.
FigletNewton

3

Цей спосіб працює для мене (за допомогою Spring Boot версії 2.0.1. RELEASE):

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

Пояснення:? 1,? 2,? 3 тощо є власниками місця першого, другого, третього параметрів і т. Д. У цьому випадку достатньо, щоб параметр був оточений%, як якщо б це був стандартний запит SQL, але без одинарні лапки.


вам слід віддати перевагу названим параметрам замість цифр:@Query("SELECT u.username FROM User u WHERE u.username LIKE %:username%")
Ральф,

0
@Query("select u from user u where u.username LIKE :username")
List<User> findUserByUsernameLike(@Param("username") String username);

Дякуємо, проблема деплоювання полягала в тому, що jpql чутливий до регістру, зараз він розгортається, але 'LIKE' працює не так, як я хочу. Він знаходить просто записи, які повністю відповідають вхідному параметру (не містять його).
Вікторія

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

Я спробував цей код, і він працює.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.