導入
findById はSpring Data JPAが最初から用意してくれていますが、「メールアドレスで探したい」「名前に特定の文字を含むものを探したい」といった独自の検索条件は、どう指定すればよいのでしょうか。
説明
Spring Data JPAには、メソッド名から自動でクエリを組み立てるという強力な機能があります。これを 派生クエリメソッド(derived query method) と呼びます。
public interface UserRepository extends JpaRepository<User, Long> {
// メソッド名から "WHERE email = ?" のクエリが自動生成される
Optional<User> findByEmail(String email);
// "WHERE name LIKE %?%" が自動生成される
List<User> findByNameContaining(String keyword);
// 複数条件も "AND" でつなげる
List<User> findByNameContainingAndAgeGreaterThan(String keyword, int age);
// 並び順も指定できる
List<User> findByOrderByCreatedAtDesc();
}
graph LR Method["findByNameContaining(String keyword)"] -->|メソッド名を解析| Parser["Spring Data JPA<br/>のクエリ生成機構"] Parser --> SQL["SELECT * FROM users<br/>WHERE name LIKE %?%"]
findBy に続けて、対象のフィールド名(Email, Name)や条件(Containing=部分一致、GreaterThan=より大きい、And=かつ)を英語の文法のようにつなげるだけで、Spring Data JPAがその意味を解析し、対応するSQLを自動生成します。開発者はメソッドのシグネチャ(名前と引数)だけを書けばよく、実装もSQLも書く必要がありません。
さらに複雑な条件や、パフォーマンスを細かく調整したい場合は、@Query を使ってJPQL(JPA独自のオブジェクト指向的なクエリ言語)やネイティブSQLを直接書くこともできます。
@Query("SELECT u FROM User u WHERE u.email = :email AND u.active = true")
Optional<User> findActiveUserByEmail(@Param("email") String email);
派生クエリメソッドは「シンプルな条件ならメソッド名だけで済む」手軽さが魅力ですが、条件が複雑になりすぎるとメソッド名が長く読みにくくなります。その場合は @Query に切り替える、という使い分けが実務では一般的です。
やってみよう
「価格が指定した値以下の商品を、価格の安い順に取得する」というメソッドを、派生クエリメソッドの命名規則で書けそうか考えてみましょう(ヒント: LessThanEqual と OrderBy...Asc を組み合わせます)。