例によるSpring Data JPAクエリ

1. 前書き

このチュートリアルでは、https://www.baeldung.com/spring-data [Spring Data] https://docs.spring.io/spring-data/jpa/を使用してデータをクエリする方法を学習します。 docs / current / reference / html /#query-by-example [サンプルAPIによるクエリ] *。
最初に、クエリするデータのスキーマを定義します。 次に、Spring Dataの関連クラスのいくつかを調べます。 それから、いくつかの例を見ていきましょう。
始めましょう!

2. テストデータ

私たちのテストデータは、乗客の名前と彼らが占有した座席のリストです。
First Name Last Name Seat Number

Jill

Smith

50

Eve

Jackson

94

Fred

Bloggs

22

Ricki

Bobbie

36

Siya

Kolisi

85

3. ドメイン

必要なlink:/spring-data-repositories[Spring Data Repository]を作成し、ドメインクラスとIDタイプを提供しましょう。
まず、_Passenger_をJPAエンティティとしてモデル化しました。
@Entity
class Passenger {

    @Id
    @GeneratedValue
    @Column(nullable = false)
    private Long id;

    @Basic(optional = false)
    @Column(nullable = false)
    private String firstName;

    @Basic(optional = false)
    @Column(nullable = false)
    private String lastName;

    @Basic(optional = false)
    @Column(nullable = false)
    private int seatNumber;

    // constructor, getters etc.
}
JPAを使用する代わりに、別の抽象化としてモデル化できます。

4. サンプルAPIによるクエリ

まず、_JpaRepository_インターフェースを見てみましょう。 ご覧のとおり、_https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/query/QueryByExampleExecutor.html [QueryByExampleExecutor] _インターフェースを拡張してクエリをサポートします例によって:
public interface JpaRepository<T, ID>
  extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {}
このインターフェイスは、Spring Dataでよく知っている_find()_メソッドのバリエーションをさらに導入しています。 ただし、各メソッドはhttps://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/domain/Example.html[_Example_]のインスタンスも受け入れます。
public interface QueryByExampleExecutor<T> {
    <S extends T> Optional<S> findOne(Example<S> var1);
    <S extends T> Iterable<S> findAll(Example<S> var1);
    <S extends T> Iterable<S> findAll(Example<S> var1, Sort var2);
    <S extends T> Page<S> findAll(Example<S> var1, Pageable var2);
    <S extends T> long count(Example<S> var1);
    <S extends T> boolean exists(Example<S> var1);
}
次に、_Example_インターフェースは、_probe_およびhttps://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/domain/ExampleMatcher.html[_ExampleMatcher_]にアクセスするためのメソッドを公開します。
_probe_が_Entity_のインスタンスであることを認識することが重要です:
public interface Example<T> {

    static <T> org.springframework.data.domain.Example<T> of(T probe) {
        return new TypedExample(probe, ExampleMatcher.matching());
    }

    static <T> org.springframework.data.domain.Example<T> of(T probe, ExampleMatcher matcher) {
        return new TypedExample(probe, matcher);
    }

    T getProbe();

    ExampleMatcher getMatcher();

    default Class<T> getProbeType() {
        return ProxyUtils.getUserClass(this.getProbe().getClass());
    }
}
要約すると、_probe_と_ExampleMatcher_は一緒にクエリを指定します。

5. 制限事項

すべてのものと同様に、Query by Example APIにはいくつかの制限があります。 例えば:
  • ネストおよびグループ化ステートメントはサポートされていません。例:
    firstName _ =?0 and_ lastName _ =?1)or_ seatNumber _ =?2_

  • 文字列の一致には、大文字と小文字を区別しない正確な開始、終了、
    含む、正規表現

  • _String_以外のすべてのタイプは完全一致のみです

    APIとその制限についてもう少し詳しくなったので、いくつかの例を見てみましょう。

6. 例

6.1. 大文字と小文字を区別するマッチング

簡単な例から始めて、デフォルトの動作について話しましょう。
@Test
public void givenPassengers_whenFindByExample_thenExpectedReturned() {
    Example<Passenger> example = Example.of(Passenger.from("Fred", "Bloggs", null));

    Optional<Passenger> actual = repository.findOne(example);

    assertTrue(actual.isPresent());
    assertEquals(Passenger.from("Fred", "Bloggs", 22), actual.get());
}
特に、静的_Example.of()_メソッドは、_ExampleMatcher.matching()_を使用して_Example_を構築します。
つまり、_Passenger_のすべてのnull以外のプロパティで*完全一致が実行されます。 したがって、一致は_String_プロパティで大文字と小文字が区別されます。
ただし、null以外のすべてのプロパティを完全に一致させることができれば、あまり便利ではありません。
これが_ExampleMatcher_の出番です。 独自のExampleMatcherを構築することにより、ニーズに合わせて動作をカスタマイズできます。

6.2. 大文字と小文字を区別しないマッチング

それを念頭に置いて、別の例を見てみましょう。今回は_withIgnoreCase()_を使用して大文字と小文字を区別しないマッチングを実現します。
@Test
public void givenPassengers_whenFindByExampleCaseInsensitiveMatcher_thenExpectedReturned() {
    ExampleMatcher caseInsensitiveExampleMatcher = ExampleMatcher.matchingAll().withIgnoreCase();
    Example<Passenger> example = Example.of(Passenger.from("fred", "bloggs", null),
      caseInsensitiveExampleMatcher);

    Optional<Passenger> actual = repository.findOne(example);

    assertTrue(actual.isPresent());
    assertEquals(Passenger.from("Fred", "Bloggs", 22), actual.get());
}
この例では、最初に_ExampleMatcher.matchingAll()–_を呼び出しましたが、前の例で使用した_ExampleMatcher.matching()_と同じ動作をしていることに注意してください。

6.3. カスタムマッチング

また、プロパティごとにマッチャーの動作を調整し、_ExampleMatcher.matchingAny()_を使用して任意のプロパティを一致させることもできます。
@Test
public void givenPassengers_whenFindByExampleCustomMatcher_thenExpectedReturned() {
    Passenger jill = Passenger.from("Jill", "Smith", 50);
    Passenger eve = Passenger.from("Eve", "Jackson", 95);
    Passenger fred = Passenger.from("Fred", "Bloggs", 22);
    Passenger siya = Passenger.from("Siya", "Kolisi", 85);
    Passenger ricki = Passenger.from("Ricki", "Bobbie", 36);

    ExampleMatcher customExampleMatcher = ExampleMatcher.matchingAny()
      .withMatcher("firstName", ExampleMatcher.GenericPropertyMatchers.contains().ignoreCase())
      .withMatcher("lastName", ExampleMatcher.GenericPropertyMatchers.contains().ignoreCase());

    Example<Passenger> example = Example.of(Passenger.from("e", "s", null), customExampleMatcher);

    List<Passenger> passengers = repository.findAll(example);

    assertThat(passengers, contains(jill, eve, fred, siya));
    assertThat(passengers, not(contains(ricki)));
}

6.4. プロパティを無視する

一方、プロパティのサブセットに対してのみクエリを実行することもできます*。
_ExampleMatcher.ignorePaths(String…paths)_を使用していくつかのプロパティを無視することでこれを実現します。
@Test
public void givenPassengers_whenFindByIgnoringMatcher_thenExpectedReturned() {
    Passenger jill = Passenger.from("Jill", "Smith", 50);
    Passenger eve = Passenger.from("Eve", "Jackson", 95);
    Passenger fred = Passenger.from("Fred", "Bloggs", 22);
    Passenger siya = Passenger.from("Siya", "Kolisi", 85);
    Passenger ricki = Passenger.from("Ricki", "Bobbie", 36);

    ExampleMatcher ignoringExampleMatcher = ExampleMatcher.matchingAny()
      .withMatcher("lastName", ExampleMatcher.GenericPropertyMatchers.startsWith().ignoreCase())
      .withIgnorePaths("firstName", "seatNumber");

    Example<Passenger> example = Example.of(Passenger.from(null, "b", null), ignoringExampleMatcher);

    List<Passenger> passengers = repository.findAll(example);

    assertThat(passengers, contains(fred, ricki));
    assertThat(passengers, not(contains(jill));
    assertThat(passengers, not(contains(eve));
    assertThat(passengers, not(contains(siya));
}

7. 結論

この記事では、サンプルAPIによるクエリの使用方法を示しました。
https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/domain/Example.html[_Example_]およびhttps:// docsの使用方法を示しました。 spring.io/spring-data/commons/docs/current/api/org/springframework/data/domain/ExampleMatcher.html[_ExampleMatcher_]とともに_https://docs.spring.io/spring-data/commons/docs /current/api/org/springframework/data/repository/query/QueryByExampleExecutor.html[QueryByExampleExecutor]_「インターフェイス」を使用して、サンプルデータインスタンスを使用してテーブルをクエリします。
結論として、https://github.com/eugenp/tutorials/tree/master/persistence-modules/spring-data-jpa [GitHubで]というコードを見つけることができます。