Spring JPA @Query avec LIKE


93

J'essaie de créer une méthode dans CrudRepository qui pourra me donner la liste des utilisateurs, dont les noms d'utilisateur sont COMME le paramètre d'entrée (non seulement commencent par, mais le contiennent également). J'ai essayé d'utiliser la méthode"findUserByUsernameLike(@Param("username") String username)" mais comme il est dit dans la documentation Spring, cette méthode est égale à " where user.username like ?1". Ce n'est pas bon pour moi, car je l'ai déjà dit que j'essaie d'obtenir tous les utilisateurs dont le nom d'utilisateur contient ...

J'ai écrit une requête à la méthode mais elle ne se déploie même pas.

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

Quelqu'un peut-il m'aider avec ça?


4
Vous voudrez peut-être utiliser containingpour bénéficier des index, voir docs.spring.io/spring-data/jpa/docs/1.4.3.RELEASE/reference

Réponses:


170

Essayez d'utiliser l'approche suivante (cela fonctionne pour moi):

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

Remarque: le nom de la table en JPQL doit commencer par une majuscule.


10
ou WHERE UPPER(u.username) LIKE CONCAT('%',UPPER(:username),'%')pour faire une recherche insensible à la casse
Brad Mace

SQL-Injection utilisant votre solution possible? (demander à cause de CONCAT)
ramden

@ramden tous @Paramsont nettoyés , donc non.
nurettin

Vous pouvez simplement faire comme: username puis .setParameter ("username", "% foo%");
Matthew Daumen

comment définir .setParameter ("username", "% foo%"); @MatthewDaumen
xuezhongyu01

120

En utilisant la création de requêtes à partir de noms de méthodes , consultez le tableau 4 où ils expliquent certains mots-clés.

  1. En utilisant J'aime: sélectionnez ... comme: nom d'utilisateur

    List<User> findByUsernameLike(String username);
  2. Démarrage avec: sélectionnez ... comme: nom d'utilisateur%

    List<User> findByUsernameStartingWith(String username);
  3. EndingWith: sélectionnez ... comme%: nom d'utilisateur

    List<User> findByUsernameEndingWith(String username);
  4. Contenant: sélectionnez ... comme%: username%

    List<User> findByUsernameContaining(String username);

Notez que la réponse que vous recherchez est le numéro 4 . Vous n'êtes pas obligé d'utiliser @Query


C'est vraiment utile, mais si je souhaite utiliser le mot clé Containing, puis-je également le rendre insensible à la casse? Dans la documentation, il y a quelque chose à propos de StringMatcher. Il semble que si j'ai créé une fonction séparée avec ExampleMatcher, cela fonctionnerait, mais puis-je le déclarer d'une manière ou d'une autre dans le nom de la méthode pour ne pas écrire ma propre fonction juste pour ajouter cette insensibilité à la casse?
V. Samma

11
Je voulais juste ajouter que vous pouvez également ignorer la casse, si nécessaire, comme ceci: List<User> findByUsernameContainingIgnoreCase(String username);
Robert

Le symbole du pourcentage doit être inversé StartingWith: select ... like :username%et EndingWith: select ... like %:username... de toute façon, une excellente réponse ... devrait être celle acceptée. Merci.
Alessandro

@Robert j'ai une colonne de données avec des majuscules et j'ai utilisé la méthode JPQL et j'ai passé une valeur en minuscules et j'ai pu obtenir les valeurs. sans IgnoreCase, il récupère également les données de cas incorrectes. Pourquoi ce comportement étrange est-il arrivé?
greenhorn

@greenhorn Veuillez ouvrir une question StackOverflow distincte et ajouter un exemple de vos données dans le tableau et ce que vous recherchez.
Robert

25

Une autre façon: à la place de la CONCATfonction, nous pouvons utiliser un double tube :: nom || '%'

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

Vous pouvez mettre n'importe où, préfixe, suffixe ou les deux

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

10

List<User> findByUsernameContainingIgnoreCase(String username);

afin d'ignorer les problèmes de cas


SQL-Injection utilisant votre solution possible?
xuezhongyu01


8

Pour votre cas, vous pouvez utiliser directement les méthodes JPA. C'est comme ci-dessous:

Contenant: sélectionnez ... comme%: username%

List<User> findByUsernameContainingIgnoreCase(String username);

ici, IgnoreCase vous aidera à rechercher l'élément en ignorant la casse.

Voici quelques méthodes associées:

  1. Comme findByFirstnameLike

    … Où x.firstname aime? 1

  2. Commençant par findByFirstnameStartingWith

    … Où x.firstname comme? 1 (paramètre lié avec% ajouté)

  3. EndingWith findByFirstnameEndingWith

    … Où x.firstname comme? 1 (paramètre lié avec% préfixé)

  4. Contenant findByFirstnameContaining

    … Où x.firstname comme? 1 (paramètre lié enveloppé dans%)

Plus d'infos, voir ce lien et ce lien

J'espère que ceci vous aidera :)


Merci! Utiliser les conventions JPA semble être la bonne manière.
FigletNewton le

3

Cette méthode fonctionne pour moi (en utilisant Spring Boot version 2.0.1. RELEASE):

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

Expliquant: Les? 1,? 2,? 3 etc. sont des espaces réservés les premier, deuxième, troisième paramètres, etc. Dans ce cas, il suffit d'avoir le paramètre entouré de% comme s'il s'agissait d'une requête SQL standard mais sans Guillemets simples.


vous devriez préférer les paramètres nommés au lieu des nombres:@Query("SELECT u.username FROM User u WHERE u.username LIKE %:username%")
Ralph le

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

Merci, le problème du déploiement était que jpql est sensible à la casse, maintenant il se déploie, mais 'LIKE' ne fonctionne pas comme je le souhaite. Il ne trouve que les enregistrements qui sont complètement égaux au paramètre d'entrée (ne le contenant pas).
Viktoriia

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

J'ai essayé ce code et cela fonctionne.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.