Spring Data JPAで、 JpaRepository を継承したリポジトリインターフェースに対し、特定の命名規則でメソッドを宣言しておくと、 @Query
アノテーションなど書かなくても処理を自動生成してくれる。
で、その命名規則、単純な検索処理であれば findAllByXxxIdAndYyyId
みたいな感じでかけるのだが、引数でコレクションを渡して検索する場合とかを毎回忘れる。
忘れた回数を数えていたら、今年に入って10回目の忘却を達成してしまったのでメモ。
どこを見ればいいか
こちら: Spring Data JPA - Reference Documentation。
Pleiades翻訳版はこちら: Spring Data JPA - リファレンスドキュメント
The JPA module supports defining a query manually as a String or having it being derived from the method name.
とあるので、日本語にすると、「メソッド名派生クエリ」とか、「メソッド名生成クエリ」とかになるのかな?
Pleiades翻訳版のほうだと、「メソッド名から派生したクエリ」になっている。
よく忘れるものをメモ
コレクション渡しでの複数条件検索
${フィールド名}In
、否定形なら ${フィールド名}NotIn
を使う。毎回 ${フィールド名}s
とか書いてエラーにしてるんだよなぁ。
引数として渡すコレクションが空の場合、 IN ()
に展開されるため、標準SQLに準拠したRDBMSならSQLエラーになる。
数年前、Spring Boot v1.5+Oracle Databaseを使っていた時、OracleのIN1つあたり1,000件上限問題は、自動では回避してくれなかった気がするが、覚えていない。
1,000件ごとに分割して、複数回実行したことがあるような気がする...
LIKE検索
複数パターンあり。
検索条件として %
や _
のワイルドカードが設定された文字列を渡す場合は ${フィールド名}Like
、否定形なら ${フィールド名}NotLike
を使う。
ワイルドカードが設定されていない文字列を渡す場合、前方一致、後方一致、部分一致で3パターンの命名方法が用意されている。
- 前方一致検索:
${フィールド名}StartingWith
で引数が文字列%
となる - 後方一致検索:
${フィールド名}EndingWith
で引数が%文字列
となる - 部分一致検索:
${フィールド名}Containing
で引数が%文字列%
となる
ざっくり、以下のようなイメージ。
String name = "example"; assert repo.findByNameLike(name + "%").equals(repo.findByNameStartingWith(name)); assert repo.findByNameLike("%" + name).equals(repo.findByNameEndingWith(name)); assert repo.findByNameLike("%" + name + "%").equals(repo.findByNameContaining(name));
GROUP BY
直接 GROUP BY
に該当するものはない。
findDistinct...
で、SELECT DISTINCT
による検索ができるので、単純な重複削除はできそう。
DELETE文
検索だけでなく、deleteBy${フィールド名}
で削除メソッドも生成できる。Derived Delete Queries、Pleiades翻訳版だと派生削除クエリという模様。
delete
以外に remove
も利用可能。 And
や Or
による複数条件も可能。
また、 @Query
で検索以外の処理を行う場合、 @Modifying
アノテーションをメソッドに付与する必要があるが、メソッド名による精製では @Modifying
不要。
なお、 @Query("DELETE ...")
+ @Modifying
と、メソッド名から生成された削除処理では、実際の挙動が異なる模様。
@Query
による削除では、JPQLから生成されたSQLを直接データベースに実行するため、JPAのライフサイクル・コールバック外の削除となり、 @PreRemove
や @PostRemove
などを付与したメソッドがあっても実行されない。
メソッド名派生による削除処理では、実際は同条件での検索処理が実行され、検索結果のJPA Entityを引数として CrudRepository#delete
を実行するという処理になるため、JPAのライフサイクル上で削除が行われ、@PreRemove
や @PostRemove
を付与したメソッドも実行されるとのこと。
振り返り
よくよく見ると、Repositoryを継承したインターフェースなら使える模様。
根本原因である「忘れる」ことについては何も解決していないが、まあ、今後はここ見ればいいからいいか...