Spring JPA @Query con LIKE


93

Estoy tratando de crear un método en CrudRepository que pueda darme una lista de usuarios, cuyos nombres de usuario son COMO el parámetro de entrada (no solo comienza con, sino que también lo contiene). Intenté usar el método "findUserByUsernameLike(@Param("username") String username)"pero como se dice en la documentación de Spring, este método es igual a " where user.username like ?1". No es bueno para mí, como ya dije que estoy tratando de obtener todos los usuarios cuyo nombre de usuario contiene ...

Escribí una consulta al método pero ni siquiera se implementa.

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

¿Puede alguien ayudarme con esto?


4
Es posible que desee utilizar containingpara beneficiarse de los índices, consulte docs.spring.io/spring-data/jpa/docs/1.4.3.RELEASE/reference/…

Respuestas:


170

Intente usar el siguiente enfoque (me funciona):

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

Aviso: el nombre de la tabla en JPQL debe comenzar con una letra mayúscula.


10
o WHERE UPPER(u.username) LIKE CONCAT('%',UPPER(:username),'%')para hacer una búsqueda que no distingue entre mayúsculas y minúsculas
Brad Mace

¿Es posible la inyección SQL utilizando su solución? (pregunta por CONCAT)
ramden

@ramden todos los @Params están desinfectados, así que no.
nurettin

Puede simplemente hacer como: nombre de usuario y luego .setParameter ("nombre de usuario", "% foo%");
Matthew Daumen

cómo configurar .setParameter ("username", "% foo%"); @MatthewDaumen
xuezhongyu01

120

Usando la creación de consultas a partir de nombres de métodos , consulte la tabla 4 donde explican algunas palabras clave.

  1. Usando Me gusta: seleccione ... como: nombre de usuario

    List<User> findByUsernameLike(String username);
  2. Comenzando con: seleccione ... como: nombre de usuario%

    List<User> findByUsernameStartingWith(String username);
  3. EndingWith: seleccione ... como%: nombre de usuario

    List<User> findByUsernameEndingWith(String username);
  4. Contiene: seleccione ... como%: username%

    List<User> findByUsernameContaining(String username);

Observe que la respuesta que busca es la número 4 . No tienes que usar @Query


Eso es realmente útil, pero si quiero usar la palabra clave Containing, ¿puedo hacer que no distinga entre mayúsculas y minúsculas? En la documentación se dice algo sobre StringMatcher. Parece que si creara una función separada con ExampleMatcher, funcionaría, pero ¿puedo de alguna manera declararlo en el nombre del método para no escribir mi propia función solo para agregar esta insensibilidad a mayúsculas y minúsculas?
V. Samma

11
Solo quería agregar que también puede ignorar el caso, si es necesario, como este: List<User> findByUsernameContainingIgnoreCase(String username);
Robert

El símbolo de porcentaje debe invertirse StartingWith: select ... like :username%y EndingWith: select ... like %:username... de todos modos, la gran respuesta ... debe ser la aceptada. Gracias.
Alessandro

@Robert tengo una columna de datos con mayúsculas y utilicé JPQL como método y pasé un valor en minúsculas y pude obtener los valores. sin IgnoreCase también está obteniendo los datos de casos incorrectos. ¿Por qué ocurrió este comportamiento extraño?
novato

@greenhorn Abra una pregunta separada de StackOverflow y agregue algún ejemplo de sus datos en la tabla y lo que está consultando.
Robert

25

Otra forma: en lugar de la CONCATfunción podemos usar tubería doble :: apellido || '%'

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

Puede poner en cualquier lugar, prefijo, sufijo o ambos

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

10

List<User> findByUsernameContainingIgnoreCase(String username);

para ignorar los problemas del caso


¿Es posible la inyección SQL utilizando su solución?
xuezhongyu01


8

Para su caso, puede utilizar directamente los métodos JPA. Eso es como un bramido:

Contiene: seleccione ... como%: username%

List<User> findByUsernameContainingIgnoreCase(String username);

aquí, IgnoreCase le ayudará a buscar el artículo ignorando el caso.

A continuación, se muestran algunos métodos relacionados:

  1. Me gusta findByFirstnameLike

    ... donde x.firstname como? 1

  2. Empezando con findByFirstnameStartingWith

    ... donde x.firstname como? 1 (parámetro enlazado con% añadido)

  3. Terminando con findByFirstnameEndingWith

    ... donde x.firstname como? 1 (parámetro enlazado con% antepuesto)

  4. Conteniendo findByFirstnameContaining

    ... donde x.firstname como? 1 (parámetro enlazado envuelto en%)

Más información, ver este enlace y este enlace

Espero que esto te ayudará :)


¡Gracias! Usar las convenciones de JPA se siente como la forma correcta.
FigletNewton

3

De esta manera funciona para mí, (usando Spring Boot versión 2.0.1. RELEASE):

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

Explicando: Los? 1,? 2,? 3, etc. son marcadores de posición del primer, segundo, tercer parámetro, etc. En este caso es suficiente tener el parámetro rodeado por% como si fuera una consulta SQL estándar pero sin el comillas simples.


debe preferir los parámetros con nombre en lugar de los 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);

Gracias, el problema de la depuración fue que jpql distingue entre mayúsculas y minúsculas, ahora se está implementando, pero 'LIKE' no funciona como quiero. Solo encuentra registros que son iguales al parámetro de entrada por completo (que no lo contienen).
Viktoriia

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

Probé este código y funciona.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.