Spring JPA @Query с LIKE

95

Я пытаюсь создать метод в CrudRepository, который сможет предоставить мне список пользователей, чьи имена похожи на входной параметр (не только начинаются с него, но также содержат его). Я пытался использовать метод, "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),'%')выполнить поиск без
Брэд Мейс
Возможна ли SQL-инъекция с использованием вашего решения? (спрашивает из-за CONCAT)
ramden 08
@ramden все @Paramпродезинфицированы, поэтому нет.
nurettin
Вы можете просто сделать следующее: имя пользователя, а затем .setParameter ("имя пользователя", "% foo%");
Мэтью
как установить .setParameter ("имя пользователя", "% foo%"); @MatthewDaumen
xuezhongyu01
122

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

  1. Использование Like: select ... like :username

     List<User> findByUsernameLike(String username);
    
  2. Начиная с: select ... like :username%

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

     List<User> findByUsernameEndingWith(String username);
    
  4. Содержит: select ... like %:username%

     List<User> findByUsernameContaining(String username);
    

Обратите внимание, что ответ, который вы ищете, - номер 4 . Вам не обязательно использовать @Query

jmgoyesc
источник
Это действительно полезно, но если я хочу использовать ключевое слово Contain, могу ли я сделать его без учета регистра? В документации что-то сказано о StringMatcher. Кажется, если бы я создал отдельную функцию с ExampleMatcher, она бы сработала, но могу ли я как-то объявить ее в имени метода, чтобы не писать свою собственную функцию только для добавления этой нечувствительности к регистру?
В.
11
Просто хотел добавить, что при необходимости вы также можете игнорировать регистр, например: List<User> findByUsernameContainingIgnoreCase(String username);
Роберт
Символ процента должен быть перевернут StartingWith: select ... like :username%и EndingWith: select ... like %:username... в любом случае отличный ответ ... должен быть принятым. Спасибо.
Алессандро
@Robert у меня есть данные столбца с прописными буквами, и я использовал метод, подобный JPQL, и передал значение в нижнем регистре и смог получить значения. без IgnoreCase также извлекаются данные о ненадлежащих случаях. Почему происходит такое странное поведение?
greenhorn
@greenhorn Пожалуйста, откройте отдельный вопрос StackOverflow и добавьте в таблицу несколько примеров ваших данных и того, что вы запрашиваете.
Роберт
25

Другой способ: вместо CONCATфункции мы можем использовать двойной канал :: lastname || '%'

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

Вы можете указать где угодно, префикс, суффикс или оба

:lastname ||'%'  
'%' || :lastname  
'%' || :lastname || '%'  
remat_br
источник
10

List<User> findByUsernameContainingIgnoreCase(String username);

чтобы игнорировать проблемы с регистром

Юсуф
источник
Возможна ли SQL-инъекция с использованием вашего решения?
xuezhongyu01
9

В вашем случае вы можете напрямую использовать методы JPA. Это похоже на ниже:

Содержит: select ... например%: username%

List<User> findByUsernameContainingIgnoreCase(String username);

здесь IgnoreCase поможет вам искать элемент без учета регистра.

Вот несколько связанных методов:

  1. подобно findByFirstnameLike

    … Где x.firstname like? 1

  2. Начиная с findByFirstnameStartingWith

    … Где x.firstname как? 1 (параметр связан с добавленным%)

  3. EndingWith findByFirstnameEndingWith

    … Где x.firstname как? 1 (параметр связан с добавлением%)

  4. Содержащий findByFirstnameContaining

    … Где x.firstname как? 1 (привязка параметра заключена в%)

Дополнительная информация, просмотрите эту ссылку и эту ссылку

Надеюсь, что это поможет вам :)

Md. Sajedul Karim
источник
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, но без одинарные кавычки.

Уислеандро
источник
1
вам следует предпочесть названные параметры вместо чисел:@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);
Mannekenpix
источник
Спасибо, проблема удаления была в том, что jpql чувствителен к регистру, сейчас он развертывается, но LIKE не работает так, как я хочу. Он находит только те записи, которые полностью равны входному параметру (не содержащие его).
Виктория
-1
@Query("select b.equipSealRegisterId from EquipSealRegister b where b.sealName like %?1% and b.deleteFlag = '0'" )
    List<String>findBySeal(String sealname);

Я пробовал этот код, и он работает.

derrick.yang
источник