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を継承したインターフェースなら使える模様。
根本原因である「忘れる」ことについては何も解決していないが、まあ、今後はここ見ればいいからいいか...