Spring JPAリポジトリのLIKEクエリ

1. 前書き

このクイックチュートリアルでは、https://www.baeldung.com/the-persistence-layer-with-spring-data-jpa [Spring JPA Repositories]でLIKEクエリを作成するさまざまな方法について説明します。
まず、クエリメソッドを作成するときに使用できるさまざまなキーワードを確認します。 次に、名前付きおよび順序付けされたパラメーターを使用して_ @ Query_アノテーションをカバーします。

2. セットアップ

この例では、_movie_テーブルをクエリします。
_Movie_エンティティを定義しましょう:
@Entity
public class Movie {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;
    private String title;
    private String director;
    private String rating;
    private int duration;

    // standard getters and setters
}
_Movie_エンティティを定義したら、サンプルのinsertステートメントを作成しましょう。
INSERT INTO movie(id, title, director, rating, duration)
    VALUES(1, 'Godzilla: King of the Monsters', ' Michael Dougherty', 'PG-13', 132);
INSERT INTO movie(id, title, director, rating, duration)
    VALUES(2, 'Avengers: Endgame', 'Anthony Russo', 'PG-13', 181);
INSERT INTO movie(id, title, director, rating, duration)
    VALUES(3, 'Captain Marvel', 'Anna Boden', 'PG-13', 123);
INSERT INTO movie(id, title, director, rating, duration)
    VALUES(4, 'Dumbo', 'Tim Burton', 'PG', 112);
INSERT INTO movie(id, title, director, rating, duration)
    VALUES(5, 'Booksmart', 'Olivia Wilde', 'R', 102);
INSERT INTO movie(id, title, director, rating, duration)
    VALUES(6, 'Aladdin', 'Guy Ritchie', 'PG', 128);
INSERT INTO movie(id, title, director, rating, duration)
    VALUES(7, 'The Sun Is Also a Star', 'Ry Russo-Young', 'PG-13', 100);

3. LIKEクエリメソッド

*多くの単純なLIKEクエリシナリオでは、さまざまなキーワードを利用してリポジトリにクエリメソッドを作成できます。*
それらを今すぐ探検しましょう。

3.1. Containing _、 Contains IsContaining_、および_Like_

クエリメソッドを使用して次のLIKEクエリを実行する方法を見てみましょう。
SELECT * FROM movie WHERE title LIKE '%in%';
最初に、_Containing _、_ Contains、_、および_IsContaining_を使用してクエリメソッドを定義します。
List<Movie> findByTitleContaining(String title);
List<Movie> findByTitleContains(String title);
List<Movie> findByTitleIsContaining(String title);
部分的なタイトル_in_でクエリメソッドを呼び出しましょう。
List<Movie> results = movieRepository.findByTitleContaining("in");
assertEquals(3, results.size());

results = movieRepository.findByTitleIsContaining("in");
assertEquals(3, results.size());

results = movieRepository.findByTitleContains("in");
assertEquals(3, results.size());
3つのメソッドのそれぞれが同じ結果を返すことが期待できます。
  • Springは_Like_キーワードも提供しますが、検索パラメーターにワイルドカード文字を指定する必要があるという点で、動作が少し異なります。*

    LIKEクエリメソッドを定義しましょう。
List<Movie> findByTitleLike(String title);
ここで、以前使用したのと同じ値を使用して、ワイルドカード文字を含めて_findByTitleLike_メソッドを呼び出しましょう。
results = movieRepository.findByTitleLike("%in%");
assertEquals(3, results.size());

3.2. StartsWith

それでは、次のクエリを見てみましょう。
SELECT * FROM Movie WHERE Rating LIKE 'PG%';
_StartsWith_キーワードを使用して、クエリメソッドを作成しましょう。
List<Movie> findByRatingStartsWith(String rating);
メソッドを定義したら、値_PG_で呼び出しましょう。
List<Movie> results = movieRepository.findByRatingStartsWith("PG");
assertEquals(6, results.size());

3.3. EndsWith

  • Springは、_EndsWith_キーワードを使用して反対の機能を提供します。*

    このクエリを考えてみましょう。
SELECT * FROM Movie WHERE director LIKE '%Burton';
それでは、_EndsWith_クエリメソッドを定義しましょう。
List<Movie> findByDirectorEndsWith(String director);
メソッドを定義したら、_Burton_パラメーターを使用して呼び出しましょう。
List<Movie> results = movieRepository.findByDirectorEndsWith("Burton");
assertEquals(1, results.size());

3.4. 大文字と小文字を区別しない

大文字小文字に関係なく、特定の文字列を含むすべてのレコードを検索することがよくあります。 SQLでは、列をすべて大文字または小文字に強制し、クエリ対象の値で同じ列を提供することでこれを実現できます。
  • Spring JPAでは、https://www.baeldung.com/spring-data-case-insensitive-queries [IgnoreCase]キーワードを他のキーワードの1つと組み合わせて使用​​できます。*

List<Movie> findByTitleContainingIgnoreCase(String title);
これで、_the_を使用してメソッドを呼び出し、小文字と大文字の両方の結果を含む結果を取得することができます。
List<Movie> results = movieRepository.findByTitleContainingIgnoreCase("the");
assertEquals(2, results.size());

3.5. Not

特定の文字列を含まないすべてのレコードを検索する場合があります。 *これを行うには、_NotContains _、_ NotContaining、_、および_NotLike_キーワードを使用できます。*
_NotContaining_を使用してクエリを定義し、_PG_を含まない評価の映画を見つけましょう:
List<Movie> findByRatingNotContaining(String rating);
それでは、新しく定義したメソッドを呼び出しましょう。
List<Movie> results = movieRepository.findByRatingNotContaining("PG");
assertEquals(1, results.size());
ディレクターが特定の文字列で始まらないレコードを検索する機能を実現するには、_NotLike_キーワードを使用して、ワイルドカードの配置の制御を保持しましょう。
List<Movie> findByDirectorNotLike(String director);
最後に、メソッドを呼び出して、監督の名前が_An_以外で始まるすべての映画を見つけましょう。
List<Movie> results = movieRepository.findByDirectorNotLike("An%");
assertEquals(5, results.size());
同様の方法で_NotLike_を使用して、_EndsWith_種類の機能と組み合わせた_Not_を実現できます。

4. _ @ Query_の使用

クエリメソッドとしては複雑すぎたり、メソッド名がとてつもなく長いクエリを作成する必要がある場合があります。 そのような場合、* https://www.baeldung.com/spring-data-jpa-query [_ @ Query_ annotation]を使用してデータベースを照会できます。*

4.1. 名前付きパラメータ

比較のために、前に定義した_findByTitleContaining_メソッドと同等のクエリを作成しましょう。
@Query("SELECT m FROM Movie m WHERE m.title LIKE %:title%")
List<Movie> searchByTitleLike(@Param("title") String title);
提供するクエリにワイルドカードを含めます。 ここでは、名前付きパラメーターを使用しているため、_ @ Param_アノテーションが重要です。

4.2. 順序付けられたパラメーター

名前付きパラメーターに加えて、クエリで順序付けられたパラメーターを使用できます。
@Query("SELECT m FROM Movie m WHERE m.rating LIKE ?1%")
List<Movie> searchByRatingStartsWith(String rating);
ワイルドカードを制御できるため、このクエリは_findByRatingStartsWith_クエリメソッドと同等です。
_PG_で始まるレーティングを持つすべての映画を見つけましょう:
List<Movie> results = movieRepository.searchByRatingStartsWith("PG");
assertEquals(6, results.size());
信頼できないデータを含むLIKEクエリで順序付けられたパラメーターを使用する場合、着信検索値をエスケープする必要があります。
Spring Boot 2.4.1以降を使用している場合、https://www.baeldung.com/spring-expression-language [SpEL] _escape_メソッドを使用できます。
@Query("SELECT m FROM Movie m WHERE m.director LIKE %?#{escape([0])} escape ?#{escapeCharacter()}")
List<Movie> searchByDirectorEndsWith(String director);
ここで、値_Burton_を使用してメソッドを呼び出しましょう。
List<Movie> results = movieRepository.searchByDirectorEndsWith("Burton");
assertEquals(1, results.size());

5. 結論

この短いチュートリアルでは、Spring JPAリポジトリでLIKEクエリを作成する方法を学びました。
最初に、提供されたキーワードを使用してクエリメソッドを作成する方法を学びました。 次に、_ @ Query_パラメーターと名前付きパラメーターと順序付きパラメーターの両方を使用して、同じタスクを実行する方法を学びました。
完全なサンプルコードはhttps://github.com/eugenp/tutorials/tree/master/persistence-modules/spring-data-jpa-2[GitHubで]で入手できます。