1. 序章

このチュートリアルでは、クエリ結果の制限についてJPAおよびSpring DataJPAで学習します。

まず、クエリするテーブルと、再現するSQLクエリを確認します。

次に、JPAとSpring DataJPAを使用してそれを実現する方法について詳しく説明します。

始めましょう!

2. テストデータ

以下に、この記事全体でクエリを実行するテーブルを示します。

私たちが答えたい質問は、「最初に占有された座席は何で、誰がそれを占有しているのか」です。

ファーストネーム 苗字 座席番号
ジル スミス 50
イブ ジャクソン 94
フレッド Bloggs 22
リッキ ボビー 36
シヤ コリシ 85

3. SQL

SQLを使用すると、次のようなクエリを作成できます。

SELECT firstName, lastName, seatNumber FROM passengers ORDER BY seatNumber LIMIT 1;

4. JPAセットアップ

JPAでは、テーブルをマップするために最初にエンティティが必要です。

@Entity
class Passenger {

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

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

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

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

    // constructor, getters etc.
}

次に、クエリコードをカプセル化するメソッドが必要です。ここでは PassengerRepositoryImpl#findOrderedBySeatNumberLimitedTo(int limit)として実装されています。

@Repository
class PassengerRepositoryImpl {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public List<Passenger> findOrderedBySeatNumberLimitedTo(int limit) {
        return entityManager.createQuery("SELECT p FROM Passenger p ORDER BY p.seatNumber",
          Passenger.class).setMaxResults(limit).getResultList();
    }
}

リポジトリメソッドでは、 EntityManager を使用して、 setMaxResults()メソッドを呼び出すQueryを作成します。

このQuery#setMaxResults の呼び出しにより、最終的に、生成されたSQLにlimitステートメントが追加されます。

select
  passenger0_.id as id1_15_,
  passenger0_.fist_name as fist_nam2_15_,
  passenger0_.last_name as last_nam3_15_,
  passenger0_.seat_number as seat_num4_15_
from passenger passenger0_ order by passenger0_.seat_number limit ?

5. SpringDataJPAを使用

SpringDataJPAを使用してSQLを生成することもできます。

5.1. 最初のまたはトップ

これにアプローチする1つの方法は、キーワードfirstまたはtop。でメソッド名の派生を使用することです。

オプションで、返される最大結果サイズとして数値を指定できます。 これを省略すると、SpringDataJPAは結果サイズを1と見なします。

どちらが最初に占有され、誰が占有しているかを知りたいので、次の2つの方法で番号を省略して取得できます。

Passenger findFirstByOrderBySeatNumberAsc();
Passenger findTopByOrderBySeatNumberAsc();

上記のように、インスタンスの結果を1つに制限する場合は、オプションを使用して結果をラップすることもできます。

Optional<Passenger> findFirstByOrderBySeatNumberAsc();
Optional<Passenger> findTopByOrderBySeatNumberAsc();

5.2. ページング可能

または、Pageableオブジェクトを使用することもできます。

Page<Passenger> page = repository.findAll(
  PageRequest.of(0, 1, Sort.by(Sort.Direction.ASC, "seatNumber")));

JpaRepository、 SimpleJpaRepository、のデフォルトの実装を見ると、 Query#setMaxResultsも呼び出されていることがわかります。

protected <S extends T > Page < S > readPage(TypedQuery < S > query, 
  Class < S > domainClass, Pageable pageable,
  @Nullable Specification < S > spec) {
    if (pageable.isPaged()) {
        query.setFirstResult((int) pageable.getOffset());
        query.setMaxResults(pageable.getPageSize());
    }

    return PageableExecutionUtils.getPage(query.getResultList(), pageable, () -> {
        return executeCountQuery(this.getCountQuery(spec, domainClass));
    });
}

5.3. 比較

これらの選択肢はどちらも、最初の top が規則を優先し、Pageableが構成を優先するという目的のSQLを生成します。

select
  passenger0_.id as id1_15_,
  passenger0_.fist_name as fist_nam2_15_,
  passenger0_.last_name as last_nam3_15_,
  passenger0_.seat_number as seat_num4_15_ 
from passenger passenger0_ order by passenger0_.seat_number asc limit ?

6. 結論

JPA でクエリ結果を制限することは、SQLとは少し異なります。 JPQLにlimitキーワードを直接含めません。

代わりに、 Query#maxResults を1回呼び出すか、キーワードfirstまたはtopSpring DataJPAに含めます。 ]メソッド名。

いつものように、コードはGitHubから入手できます。