JPA – 自動生成クエリのメソッドの命名ルール

JPAはメソッド名からクエリを生成してくれるようですが、これは本当にびっくりしたので、メモしていこうと思います。

メソッドで生成キーワード

キーワードサンプルJPQL スニペット
DistinctfindDistinctByLastnameAndFirstnameselect distinct …​ where x.lastname = ?1 and x.firstname = ?2
AndfindByLastnameAndFirstname… where x.lastname = ?1 and x.firstname = ?2
OrfindByLastnameOrFirstname… where x.lastname = ?1 or x.firstname = ?2
IsEqualsfindByFirstnamefindByFirstnameIsfindByFirstnameEquals… where x.firstname = ?1
BetweenfindByStartDateBetween… where x.startDate between ?1 and ?2
LessThanfindByAgeLessThan… where x.age < ?1
LessThanEqualfindByAgeLessThanEqual… where x.age <= ?1
GreaterThanfindByAgeGreaterThan… where x.age > ?1
GreaterThanEqualfindByAgeGreaterThanEqual… where x.age >= ?1
AfterfindByStartDateAfter… where x.startDate > ?1
BeforefindByStartDateBefore… where x.startDate < ?1
IsNullNullfindByAge(Is)Null… where x.age is null
IsNotNullNotNullfindByAge(Is)NotNull… where x.age not null
LikefindByFirstnameLike… where x.firstname like ?1
NotLikefindByFirstnameNotLike… where x.firstname not like ?1
StartingWithfindByFirstnameStartingWith… where x.firstname like ?1 ( % が付加されたパラメーター)
EndingWithfindByFirstnameEndingWith… where x.firstname like ?1 ( % が先頭に追加されたパラメーター)
ContainingfindByFirstnameContaining… where x.firstname like ?1 ( % にラップされたパラメーターバインド)
OrderByfindByAgeOrderByLastnameDesc… where x.age = ?1 order by x.lastname desc
NotfindByLastnameNot… where x.lastname <> ?1
InfindByAgeIn(Collection<Age> ages)… where x.age in ?1
NotInfindByAgeNotIn(Collection<Age> ages)… where x.age not in ?1
TruefindByActiveTrue()… where x.active = true
FalsefindByActiveFalse()… where x.active = false
IgnoreCasefindByFirstnameIgnoreCase… where UPPER(x.firstname) = UPPER(?1)
https://spring.pleiades.io/spring-data/jpa/docs/current/reference/html/#reference

使い方の例

https://qiita.com/shindo_ryo/items/af7d12be264c2cc4b252

Is / Equals / Not

EmployeeRepository.java

    // SELECT e FROM Employee e
    Employee findById(Long id);

    // SELECT e FROM Employee e WHERE e.firstname = ?1 
    List<Employee> findByFirstnameEquals(String firstname);

    // SELECT e FROM Employee e WHERE e.age = ?1
    List<Employee> findByAgeIs(int age);

    // SELECT e FROM Employee e WHERE e.lastname != ?1
    List<Employee> findByLastnameNot(String lastname);

    // SELECT e FROM Employee e WHERE e.department = ?1
    List<Employee> findByDepartment(Department department);

フィールドのあとにEquals/Isをつけると完全一致、Notをつけると不一致のレコードを探索します。
大文字小文字が区別されるかは、データベースの照合順序などに依存します。

LessThan / GreaterThan

使用するキーワードはLessThan GreaterThanです。EmployeeRepository.java

    // SELECT e FROM Employee e WHERE e.age < ?1
    List<Employee> findByAgeLessThan(int age);

    // SELECT e FROM Employee e WHERE e.age > ?1
    List<Employee> findByAgeGreaterThan(String firstname);

    // SELECT e FROM Employee e WHERE e.hiredAt > ?1
    List<Employee> findByHiredAtGreaterThan(Date date);

境界値を含む場合は上述のキーワードに「Equal」を足して GreaterThanEqual LessThanEqualとします。
また、 Between キーワードで境界値を含んだ範囲検索が可能です。EmployeeRepository.java

    // SELECT e FROM Employee WHERE e.age <= ?1
    List<Employee> findByAgeLessThanEqual(int age);

    // SELECT e FROM Employee WHERE e.age >= ?1
    List<Employee> findByAgeGreaterThanEqual(int age);

    // SELECT e FROM Employee WHERE e.hiredAt BETWEEN ?1 AND ?2
    List<Employee> findByHiredAtBetween(Date since, Date until);

ちなみに、findByFirstnameLessThan(String name) のように、String型のフィールドにLessThan, GreaterThanをつけることも可能です。結果はDBMS依存になると思いますが。。

Like / NotLike / StartingWith / EndingWith / Containing

    // SELECT e FROM Employee WHERE e.firstname LIKE ?1
    List<Employee> findByFirstnameLike(int age);

    // SELECT e FROM Employee WHERE e.firstname NOT LIKE ?1
    List<Employee> findByFirstnameNotLike(String firstname);

    // SELECT e FROM Employee WHERE e.lastname LIKE ?1 (前方一致)
    List<Employee> findByLastnameStartingWith(String lastname);

    // SELECT e FROM Employee WHERE e.lastname LIKE ?1 (後方一致)
    List<Employee> findByLastnameEndingWith(String lastname);

    // SELECT e FROM Employee WHERE e.lastname LIKE ?1 (部分一致)
    List<Employee> findByLastnameContaining(String lastname);

ワイルドカードを使用した部分一致検索は、Like NotLike StartingWith EndingWith Containing を使用します。

このうち、StartingWith EndingWith Containing については、それぞれ順番に、前方一致、後方一致、部分一致となります。
任意の位置にワイルドカードを挿入した場合はLike NotLike を使用してください。

Between

    // SELECT e FROM Employee e WHERE e.age BETWEEN ?1 AND ?2
    List<Employee> findByAgeBetween(int olderThan, int youngerThan);

    // SELECT e FROM Employee e WHERE e.hiredAt BETWEEN ?1 AND ?2
    List<Employee> findByHiredAtBetween(Date since, Date until);

IsNull / (Is)NotNull

    // SELECT e FROM Employee WHERE e.hiredAt IS NULL
    List<Employee> findByHiredAtIsNull();

    // SELECT e FROM Employee WHERE e.hiredAt IS NOT NULL
    List<Employee> findByHiredAtIsNotNull();

    // SELECT e FROM Employee WHERE e.hiredAt IS NOT NULL
    List<Employee> findByHiredAtNotNull();

True / False

    // SELECT e FROM Employee WHERE e.active = true
    List<Employee> findByActiveTrue();

    // SELECT e FROM Employee WHERE e.active = false
    List<Employee> findByActiveFalse();

IN

    // SELECT e FROM Employee WHERE e.lastname in ?1
    List<Employee> findByLastnameIn(List<String> lastname);

複数の候補値で検索する場合はSQLと同じくInを使います。

After / Before

    // SELECT e FROM Employee WHERE e.lastname > ?1
    List<Employee> findByHiredAtAfter(Date date);

    // SELECT e FROM Employee WHERE e.lastname < ?1
    List<Employee> findByHiredAtBefore(Date date);

日付の比較にはLessThan(Equal) GreaterThan(Equal)が使えますが、After Beforeでも表現可能です。

OrderBy

    // SELECT e FROM Employee e WHERE e.lastname = ?1 ORDER BY e.age
    List<Employee> findByLastnameOrderByAge(String lastname);

    // SELECT e FROM Employee e WHERE e.firstname = ?1 ORDER BY e.firstname ASC
    List<Employee> findByFirstnameOrderByHiredAtAsc(String firstname);

抽出結果をソートしたい場合はOrderByを使用します。フィールド名はOrderByのうしろに置きます。昇順降順はさらにフィールド名のうしろに置くので、OrderBy+フィールド名+Asc(Desc)となります。

    // SELECT e FROM Employee e WHERE e.lastname = ?1 ORDER BY e.age ASC, e.firstname DESC
    List<Employee> findByLastnameOrderByAgeAscFirstnameDesc(String lastname);

複数のフィールドでソートする場合は、Asc Descを指定して、下記のようにつなげればOKです。

Top / First

    Employee findFirstByLastname(String lastname);

    Employee findTopByLastname(String lastname);

    List<Employee> findFirst3ByActiveTrueOrderByAgeDesc();

    List<Employee> findTop5ByHiredAtIs(Date date);

findの直後にFirstTopをつけることで件数を絞ることができます。

組み合わせて使う

    // SELECT e FROM Employee e WHERE e.age = ?1, e.active = true
    List<Employee> findByAgeIsAndActiveTrue(int age);

    // SELECT e FROM Employee e WHERE e.lastname LIKE ?1 OR e.lastname LIKE ?2
    List<Employee> findByLastnameStartingWithOrFirstnameEndingWith(String lastname, String firstname);

    // SELECT e FROM Employee e WHERE e.age BETWEEN ?1 AND ?2 AND e.department = ?3
    List<Employee> findByAgeBetweenAndDepartmentIs(int startAge, int endAge, Department depar

キーワードの組み合わせができます。

終わりに

使い方はこちらから持ってきました。詳しくできているのでそちらを参考にしてください。この記事は、忘れるかもしれないので、メモとして残した記事です。

参考

https://qiita.com/shindo_ryo/items/af7d12be264c2cc4b252

https://www.baeldung.com/tag/jpa/

https://spring.pleiades.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation

コメントを残す