以前の投稿で、「GroovyでMapperを書くことでアノテーション内にSQLを指定する方法」を紹介しましたが、動的SQLは書けないの?と思った方もいるかもしれません。私も実は知らなかったのですが・・・アノテーションでもXMLと同様に動的SQLが書けます。デフォルトではXML形式の動的SQLがサポートされています。
本投稿ではGroovyでMapperを作った時のサンプルになっていますが、もちろんJavaでつくっても同じことができます。
どうやって動的SQLを指定するの?
こんな感じです。
@Select('''
<script>
SELECT
id, title, details, finished
FROM
todo
<where>
<if test="title != null">
AND title = #{title}
</if>
<if test="details != null">
AND details = #{details}
</if>
<if test="finished != null">
AND finished = #{finished}
</if>
</where>
</script>
''')
List<Todo> findBy(@Param("title") String title
, @Param("details") String details
, @Param("finished") Boolean finished)
ポイントは、<script>
要素でSQLを囲むことです。<script>
要素でSQLを囲むと、動的SQLを組み立てるためのXML要素が使えるようになります。
アノテーション内で指定できるのはXML形式だけなの?
MyBatisの標準APIではXML形式だけですが、FreeMarkerとVelocityも拡張ライブラリとしてサポートされています。本投稿では使い方の紹介はしませんが、興味がある方はそれぞれ以下のページを参照してください。
他の方法で動的SQLは組み立てられないの?
ロジックで動的SQLを組み立てることもできます。
@SelectProvider(type = SqlProvider.class, method = "findBy")
List<Todo> findBy(@Param("title") String title
, @Param("details") String details
, @Param("finished") Boolean finished)
class SqlProvider {
String findBy(@Param("title") String title
, @Param("details") String details
, @Param("finished") Boolean finished) {
new SQL() {
{
SELECT("id, title, details, finished")
FROM("todo")
if (title != null) {
WHERE("title = #{title}")
}
if (details != null) {
WHERE("details = #{details}")
}
if (finished != null) {
WHERE("finished = #{finished}")
}
}
}.toString()
}
}
ポイントは、SqlProvider(@SelectProvider
などのアノテーション)を使うことです。
まとめ
紹介してみたものの・・・個人的には、XML形式に比べてタイプセーフな実装になるSqlProviderを使う方が好きです。
アノテーション内だとXML要素のコード補完が利用できないのでタイプミスなどの単純ミスも生れやすそう。