1. 概要

このクイックチュートリアルでは、SpringJPAリポジトリで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 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では、IgnoreCaseキーワードを他のキーワードの1つと組み合わせて使用できます

List<Movie> findByTitleContainingIgnoreCase(String title);

これで、 the を使用してメソッドを呼び出し、小文字と大文字の両方の結果を含む結果を取得できると期待できます。

List<Movie> results = movieRepository.findByTitleContainingIgnoreCase("the");
assertEquals(2, results.size());

3.5. しない

特定の文字列を含まないすべてのレコードを検索したい場合があります。 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を使用する

クエリメソッドには複雑すぎるクエリを作成する必要がある場合や、メソッド名が途方もなく長くなる場合があります。 そのような場合、@Queryアノテーションを使用してデータベースにクエリを実行できます。

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以降を使用している場合は、 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. 結論

この短い記事では、SpringJPAリポジトリーでLIKEクエリを作成する方法を学びました。

まず、提供されたキーワードを使用してクエリメソッドを作成する方法を学びました。

次に、 @Query パラメーターを名前付きパラメーターと順序付きパラメーターの両方で使用して、同じタスクを実行する方法を学習しました。

完全なサンプルコードは、GitHubから入手できます。