JPAとSpring Data JPAによるクエリ結果の制限

JPAおよびSpring Data JPAを使用したクエリ結果の制限

1. 前書き

このチュートリアルでは、JPASpring Data JPAを使用してlearn about limiting query resultsに移動します。

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

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

始めましょう!

2. テストデータ

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

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

ファーストネーム

苗字

座席番号

Jill

スミス

50

Eve

ジャクソン

94

Fred

Bloggs

22

リッキ

ボビー

36

Siya

コリシ

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 findOrderedBySeatNumberLimitedTo(int limit) {
        return entityManager.createQuery("SELECT p FROM Passenger p ORDER BY p.seatNumber",
          Passenger.class).setMaxResults(limit).getResultList();
    }
}

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

この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. Spring Data JPAを使用

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

5.1. firstまたはtop

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

必要に応じて、返される結果の最大サイズとして数値を指定できます。 省略すると、Spring Data JPAは結果サイズを1と想定します。

最初に占有された座席が何で、誰が占有しているかを知りたいことを思い出して、次の2つの方法で番号を省略して取得できます。

Passenger findFirstByOrderBySeatNumberAsc();
Passenger findTopByOrderBySeatNumberAsc();

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

Optional findFirstByOrderBySeatNumberAsc();
Optional findTopByOrderBySeatNumberAsc();

5.2. Pageable

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

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

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

protected  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. 比較

これらの選択肢はどちらも、後の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 ?

first topは規則を優先し、Pageableは構成を優先します。

6. 結論

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

代わりに、Query#maxResultsに対して単一のメソッド呼び出しを行うか、Spring Data JPAメソッド名にキーワードfirstまたはtopを含めます。

いつものように、コードover on GitHubを見つけることができます。