- Web Engineer
- アウトバウンド営業
- Webエンジニア(経験者)
- Other occupations (19)
- Development
- Business
Roomで動的クエリを使いたい時だってある
(株)ライトコードでモバイルアプリケーションメインで色々開発している笹川(ささがわ)です!
Androidアプリ開発でRoomを使っていると、@Query
アノテーションで静的なSQLを定義する場面が多いですよね。
ほとんどのケースではこれで十分なのですが、アプリの機能が複雑になってくると、次のような要望が出てくることがあります。
- ユーザーの入力に応じて検索条件を柔軟に変えたい
- 特定の条件を満たすデータだけを動的に絞り込みたい
LIKE
やGLOB
など、より高度な文字列検索をカスタマイズしたい
このような場合、事前に定義された @Query
だけでは対応が難しいことがあります。
そこで今回は、Kotlinのコード内でSQL構文を動的に構築し、Roomで実行するための方法について、具体的な手順とともに解説していきます。
なぜ動的なSQLクエリが必要になるのか
Roomの @Query
アノテーションは非常に便利ですが、SQL文自体は固定です。
例えば、ユーザーが入力したキーワードの数や種類によって WHERE
句の条件を増やしたり、並び順を動的に変更したりするようなケースでは、静的な@Query
だけでは対応しきれません。
私自身も、検索機能の実装で「複数のキーワードでAND検索したい」「特定の状態のデータをフィルタリングしたい」といった要件に直面しました。
最初は複数の@Query
を用意する方法を考えましたが、条件の組み合わせが増えるほど@Dao
インターフェースが肥大化してしまい、管理が難しくなるという課題がありました。
この経験から、KotlinコードでSQLを組み立てて動的に実行するというアプローチの重要性を痛感しました。
これにより、複雑な検索条件にも柔軟に対応でき、コードの重複を減らすことにも繋がります。
Roomで動的クエリを扱う主役:@RawQueryアノテーション
Roomで動的にSQLクエリを実行するために使うのが、@RawQuery
アノテーションです。これは、任意のSQLクエリ文字列を受け取って実行できる、強力な機能です。
RawQueryの使い方
まず、@Dao
インターフェースに@RawQuery
を付与したメソッドを定義します。このメソッドは、引数としてSupportSQLiteQuery
型のオブジェクトを受け取ります。
interface MyDao {
/*
* 動的に構築されたクエリを実行する例
* @param query SQLクエリを保持するSupportSQLiteQueryオブジェクト
*/
@RawQuery
suspend fun executeDynamicQuery(query: SupportSQLiteQuery): List<MyEntity>
// 必要に応じて、他のRoomメソッドも定義
// @Query("SELECT * FROM my_entities WHERE id = :id")
// suspend fun getById(id: Long?): MyEntity? // 例としてNullableも追加
}
ここで重要なのは、executeDynamicQuery
メソッドがSupportSQLiteQuery
を受け取る点です。このSupportSQLiteQuery
のインスタンスをKotlinコード内で生成し、動的にSQLクエリを構築していきます。
KotlinコードでSQL構文を動的に構築する手順
それでは、具体的なSQL構文の構築手順を見ていきましょう。今回は、複数のキーワードでAND検索を行う例を考えます。
1. 検索キーワードの準備と制約チェック
まず、ユーザーから入力された検索キーワードを処理します。
全角スペースを半角スペースに変換したり、複数のキーワードに分割したり、不要な空白を除去するといった前処理が考えられます。
また、検索キーワードの数に上限を設けることも重要です。
これは、SQLiteのクエリパラメータ数の上限(デフォルト999個)など、データベースの制約に起因するパフォーマンス問題やエラーを防ぐためです。
// 例: ユーザー入力から取得したキーワード文字列
val userInputKeyword = "Kotlin Room Android"
val queryKeywords = if (userInputKeyword.isNotEmpty()) {
userInputKeyword.replace(" ".toRegex(), " ") // 全角スペースを半角に
.split(" ".toRegex()) // 半角スペースで分割
.filter { it.isNotBlank() } // 空白のキーワードを除去
} else emptyList()
// SQLiteのパラメータ数上限などを考慮し、キーワード数に上限を設ける
val KEYWORD_LIMIT_SIZE = 10 // 例えば、最大10個のキーワードを許容
if (queryKeywords.size > KEYWORD_LIMIT_SIZE) {
// ここでエラーを通知したり、処理を中断する
// throw CustomKeywordLimitExceededException("キーワードが多すぎます。最大${KEYWORD_LIMIT_SIZE}個までです。")
println("キーワードが上限を超えています。検索条件を絞ってください。")
return // あるいはエラーを返す
}
2. SQLクエリの基本構文を組み立てる
次に、検索キーワードの数に応じて、動的にWHERE
句を組み立てていきます。
今回は、LIKE
句とGLOB
句を組み合わせて、より厳密なキーワード検索(大文字・小文字を区別したり、単語の区切りを考慮したり)を行う例です。
ポイントは、文字列結合ではなく、プレースホルダ(?
)と引数リストを使用することです。
後述しますが、これはSQLインジェクションを防ぐ上で非常に重要です。
…
記事の続きは下のURLをクリック!
https://rightcode.co.jp/blogs/52566
エンジニア積極採用中です!
現在、WEBエンジニア、モバイルエンジニア、デザイナー、営業などを積極採用中です!
採用ページはこちら:https://rightcode.co.jp/recruit
社員の声や社風などを知りたい方はこちら:https://rightcode.co.jp/blogs?category=life
フリーランスエンジニア大募集中!
現在、「WEBエンジニア」「フロントエンジニア」「データサイエンティスト」など、様々な職種のフリーランスエンジニア様を募集中です。まずは以下よりお気軽にご応募ください!
採用ページはこちら:https://itanken.com/register
社長と一杯飲みながらお話しませんか?(転職者向け)
特設ページはこちら: https://rightcode.co.jp/gohan-sake-president-talk
もっとワクワクしたいあなたへ
現在、ライトコードでは「WEBエンジニア」「モバイルエンジニア」「ゲームエンジニア」、「デザイナー」「WEBディレクター」「営業」などを積極採用中です!
ライトコードは技術力に定評のある受託開発をメインにしているIT企業です。
有名WEBサービスやアプリの受託開発などの企画、開発案件が目白押しの状況です。
- もっと大きなことに挑戦したい!
- エンジニアとしてもっと成長したい!
- モダンな技術に触れたい!
現状に満足していない方は、まずは、エンジニアとしても第一線を走り続ける弊社代表と気軽にお話してみませんか?
ネット上では、ちょっとユルそうな会社に感じると思いますが(笑)、
実は技術力に定評があり、沢山の実績を残している会社ということをお伝えしたいと思っております。
- ライトコードの魅力を知っていただきたい!
- 社風や文化なども知っていただきたい!
- 技術に対して熱意のある方に入社していただきたい!
一度、【Wantedly内の弊社ページ】や【コーポレートサイト】をのぞいてみてください。
Wantedly:https://www.wantedly.com/companies/rightcode
コーポレート:https://rightcode.co.jp/