Spring JPA @Query com LIKE

92

Estou tentando fazer um método em CrudRepository que será capaz de me dar uma lista de usuários, cujos nomes de usuário são como o parâmetro de entrada (não só começa com, mas também o contém). Tentei usar o método, "findUserByUsernameLike(@Param("username") String username)"mas como é dito na documentação do Spring, esse método é igual a " where user.username like ?1". Não é bom para mim, como já disse que estou tentando obter todos os usuários cujo nome de usuário contenha ...

Eu escrevi uma consulta ao método, mas nem mesmo implanta.

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

Alguém pode me ajudar com isso?

Viktoriia
fonte
4
Você pode querer usar containingpara se beneficiar dos índices, consulte docs.spring.io/spring-data/jpa/docs/1.4.3.RELEASE/reference/…

Respostas:

168

Tente usar a seguinte abordagem (funciona para mim):

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

Aviso: o nome da tabela em JPQL deve começar com letra maiúscula.

Marca
fonte
10
ou WHERE UPPER(u.username) LIKE CONCAT('%',UPPER(:username),'%')para fazer uma pesquisa que não diferencia maiúsculas de minúsculas
Brad Mace
SQL-Injection usando sua solução é possível? (perguntando por causa da CONCAT)
Ramden
@ramden todos os @Params são higienizados, então não.
nurettin de
Você pode apenas fazer como: username e, em seguida, .setParameter ("username", "% foo%");
Matthew Daumen
como definir .setParameter ("username", "% foo%"); @MatthewDaumen
xuezhongyu01
115

Usando a criação de consulta a partir de nomes de métodos , verifique a tabela 4, onde explicam algumas palavras-chave.

  1. Usando Curtir: selecione ... como: nome de usuário

    List<User> findByUsernameLike(String username);
  2. Começando com: selecione ... como: nome de usuário%

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

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

    List<User> findByUsernameContaining(String username);

Observe que a resposta que você está procurando é a número 4 . Você não precisa usar @Query

jmgoyesc
fonte
Isso é muito útil, mas se eu quiser usar a palavra-chave Contendo, também posso torná-la indiferente a maiúsculas? Na documentação, há algo dito sobre StringMatcher. Parece que se eu criasse uma função separada com ExampleMatcher ela funcionaria, mas posso de alguma forma declará-la no nome do método para não escrever minha própria função apenas para adicionar essa diferenciação de maiúsculas e minúsculas?
V. Samma
11
Só queria acrescentar que você também pode ignorar maiúsculas e minúsculas, se necessário, como este: List<User> findByUsernameContainingIgnoreCase(String username);
Robert,
O símbolo de porcentagem deve ser invertido StartingWith: select ... like :username%e EndingWith: select ... like %:username... de qualquer maneira ótima resposta ... deve ser a aceita. Obrigado.
Alessandro
@Robert eu tenho uma coluna de dados com maiúsculas e usei o método JPQL e passei o valor em minúsculas e consegui obter os valores. sem IgnoreCase também está buscando os dados de casos impróprios. Por que esse comportamento estranho aconteceu?
novato
@greenhorn Abra uma pergunta separada do StackOverflow e adicione alguns exemplos de seus dados na tabela e o que você está consultando.
Robert
25

Outra maneira: em vez da CONCATfunção, podemos usar tubo duplo :: sobrenome || '%'

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

Você pode colocar em qualquer lugar, prefixo, sufixo ou ambos

:lastname ||'%'  
'%' || :lastname  
'%' || :lastname || '%'  
remat_br
fonte
10

List<User> findByUsernameContainingIgnoreCase(String username);

a fim de ignorar problemas de caso

Yusuf
fonte
SQL-Injection usando sua solução é possível?
xuezhongyu01
8

Para o seu caso, você pode usar métodos JPA diretamente. É como abaixo:

Contendo: select ... like%: username%

List<User> findByUsernameContainingIgnoreCase(String username);

aqui, IgnoreCase irá ajudá-lo a pesquisar o item ignorando o caso.

Aqui estão alguns métodos relacionados:

  1. Gostar findByFirstnameLike

    … Onde x.firstname gosta? 1

  2. Começando com findByFirstnameStartingWith

    … Onde x.firstname like? 1 (parâmetro vinculado a% anexado)

  3. EndingWith findByFirstnameEndingWith

    … Onde x.firstname like? 1 (parâmetro vinculado a% prefixado)

  4. Contendo findByFirstnameContaining

    … Onde x.firstname like? 1 (limite de parâmetro envolvido em%)

Mais informações, veja este link e este link

Espero que isso ajude você :)

Md. Sajedul Karim
fonte
Obrigado! Usar as convenções JPA parece o caminho certo.
FigletNewton
3

Esta maneira funciona para mim, (usando Spring Boot versão 2.0.1. RELEASE):

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

Explicando: O? 1,? 2,? 3 etc. são espaços reservados para o primeiro, segundo, terceiro parâmetros, etc. Neste caso é suficiente ter o parâmetro cercado por% como se fosse uma consulta SQL padrão, mas sem o aspas simples.

Uisleandro
fonte
você deve preferir os parâmetros nomeados em vez dos números:@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);
Mannekenpix
fonte
Obrigado, o problema de deplouing era que jpql diferencia maiúsculas de minúsculas, agora ele está implantando, mas 'LIKE' não funciona como eu desejo. Ele encontra apenas os registros que são completamente iguais ao parâmetro de entrada (não o contém).
Viktoriia
-1
@Query("select b.equipSealRegisterId from EquipSealRegister b where b.sealName like %?1% and b.deleteFlag = '0'" )
    List<String>findBySeal(String sealname);

Eu tentei este código e funciona.

derrick.yang
fonte