Spring JPA @Query mit LIKE


92

Ich versuche, eine Methode in CrudRepository zu erstellen, die mir eine Liste von Benutzern geben kann, deren Benutzernamen WIE der Eingabeparameter sind (nicht nur damit beginnen, sondern ihn auch enthalten). Ich habe versucht, die Methode zu verwenden, "findUserByUsernameLike(@Param("username") String username)"aber wie in der Spring-Dokumentation angegeben, ist diese Methode gleich " where user.username like ?1". Es ist nicht gut für mich, da ich bereits gesagt habe, dass ich versuche, alle Benutzer zu finden, deren Benutzername ...

Ich habe eine Abfrage zu der Methode geschrieben, die jedoch nicht bereitgestellt wird.

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

Kann mir jemand dabei helfen?


4
Sie können verwenden, containingum von Indizes zu profitieren, siehe docs.spring.io/spring-data/jpa/docs/1.4.3.RELEASE/reference/…

Antworten:


168

Versuchen Sie, den folgenden Ansatz zu verwenden (er funktioniert bei mir):

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

Hinweis: Der Tabellenname in JPQL muss mit einem Großbuchstaben beginnen.


10
oder WHERE UPPER(u.username) LIKE CONCAT('%',UPPER(:username),'%')um eine Suche ohne
Brad Mace

SQL-Injection mit Ihrer Lösung möglich? (Fragen wegen CONCAT)
Ramden

@ramden alle @Params sind bereinigt, also nein.
Nurettin

Sie können einfach Folgendes tun: Benutzername und dann .setParameter ("Benutzername", "% foo%");
Matthew Daumen

wie man .setParameter setzt ("Benutzername", "% foo%"); @ MatthewDaumen
Xuezhongyu01

113

Überprüfen Sie mithilfe der Abfrageerstellung aus Methodennamen Tabelle 4, in der einige Schlüsselwörter erläutert werden.

  1. Verwenden von Like: Wählen Sie ... like: Benutzername

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

    List<User> findByUsernameStartingWith(String username);
  3. EndingWith: Wählen Sie ... wie%: Benutzername

    List<User> findByUsernameEndingWith(String username);
  4. Enthält: Wählen Sie ... wie%: Benutzername%

    List<User> findByUsernameContaining(String username);

Beachten Sie, dass die gesuchte Antwort Nummer 4 ist . Sie müssen @Query nicht verwenden


Das ist wirklich hilfreich, aber wenn ich das Schlüsselwort Containing verwenden möchte, kann ich es auch ohne Berücksichtigung der Groß- und Kleinschreibung machen? In der Dokumentation wird etwas über StringMatcher gesagt. Es scheint, als würde es funktionieren, wenn ich mit ExampleMatcher eine separate Funktion erstellen würde, aber kann ich es irgendwie im Methodennamen deklarieren, meine eigene Funktion nicht nur zum Hinzufügen dieser Groß- und Kleinschreibung zu schreiben?
V. Samma

11
Ich wollte nur hinzufügen, dass Sie bei Bedarf auch Groß- und Kleinschreibung ignorieren können: List<User> findByUsernameContainingIgnoreCase(String username);
Robert

Das Prozentzeichen sollte invertiert werden StartingWith: select ... like :username%und EndingWith: select ... like %:username... trotzdem eine gute Antwort ... sollte die akzeptierte sein. Vielen Dank.
Alessandro

@ Robert Ich habe eine Spalte Daten in Großbuchstaben und ich habe JPQL-ähnliche Methode verwendet und Kleinbuchstaben übergeben und in der Lage, die Werte zu erhalten. ohne IgnoreCase werden auch die unzulässigen Falldaten abgerufen. Warum ist dieses seltsame Verhalten passiert?
Greenhorn

@greenhorn Bitte öffnen Sie eine separate StackOverflow-Frage und fügen Sie ein Beispiel Ihrer Daten in die Tabelle ein und was Sie abfragen.
Robert

24

Ein anderer Weg: Stattdessen CONCATkönnen wir Double Pipe verwenden :: lastname || '%'

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

Sie können überall ein Präfix, Suffix oder beides einfügen

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

10

List<User> findByUsernameContainingIgnoreCase(String username);

um Fallprobleme zu ignorieren


SQL-Injection mit Ihrer Lösung möglich?
Xuezhongyu01


8

Für Ihren Fall können Sie direkt JPA-Methoden verwenden. Das ist wie unten:

Enthält: Wählen Sie ... wie%: Benutzername%

List<User> findByUsernameContainingIgnoreCase(String username);

Hier hilft Ihnen IgnoreCase bei der Suche nach Elementen, wobei der Fall ignoriert wird.

Hier sind einige verwandte Methoden:

  1. Mögen findByFirstnameLike

    … Wo x.firstname wie? 1

  2. Beginnen mit findByFirstnameStartingWith

    … Wo x.firstname wie? 1 (Parameter mit angehängtem% gebunden)

  3. EndingWith findByFirstnameEndingWith

    … Wo x.firstname wie? 1 (Parameter mit vorangestelltem% gebunden)

  4. Enthält findByFirstnameContaining

    … Wo x.firstname wie? 1 (Parameter in% eingeschlossen)

Weitere Informationen finden Sie unter diesem Link und diesem Link

Hoffe das wird dir helfen :)


Vielen Dank! Die Verwendung von JPA-Konventionen scheint der richtige Weg zu sein.
FigletNewton

3

Dieser Weg funktioniert bei mir (mit 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);

Erklären: Die? 1,? 2,? 3 usw. sind Platzhalter für den ersten, zweiten, dritten Parameter usw. In diesem Fall reicht es aus, wenn der Parameter von% umgeben ist, als wäre es eine Standard-SQL-Abfrage, jedoch ohne Einzelzitate.


Sie sollten die genannten Parameter anstelle der Zahlen bevorzugen:@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);

Vielen Dank, das Problem beim Deplouing war, dass bei jpql zwischen Groß- und Kleinschreibung unterschieden wird. Jetzt wird es bereitgestellt, aber 'LIKE' funktioniert nicht wie gewünscht. Es werden nur Datensätze gefunden, die dem Eingabeparameter vollständig entsprechen (ohne ihn zu enthalten).
Viktoriia

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

Ich habe diesen Code ausprobiert und er funktioniert.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.