利用すべきでないケース
使いどころの前に、まず使うべきではないケースについて説明します。RawQueryのドキュメントには以下のサンプルコードが記載されていますが、どれも基本的には利用すべきではないです。
- Observable Queries
- Returning POJOs
- POJOs with Embedded Fields
- Relations
適切にプレースホルダを利用すれば、これらのほとんどのクエリを他の@Query
等のアノテーションでも実現できます。@RawQuery
を利用してしまうとコンパイル時のバリデーションが出来ないため、Roomのメリットを捨てることになります。
使いどころ
Roomの他の機能を利用して、どうしても実現できない場合には@RawQuery
の出番です。
PRAGMA
PRAGMAの利用が@RawQuery
を利用したいケースの中でかなり多いのではないかと思います。例えばPRAGMA compile_options
というクエリで、SQLiteのコンパイルオプションの一覧を取得することが出来ます。
例として、SQLiteの全文検索(FTS)のクエリの構文を決定するコンパイルオプション(SQLITE_ENABLE_FTS3_PARENTHESIS
)の取得をしてみます。
@Dao
abstract class MyDao {
val isEnhancedQueryEnabled: Boolean by lazy {
// PRAGMAでコンパイルオプションを取得すると"SQLITE_"のプレフィックスが省略されます。
"ENABLE_FTS3_PARENTHESIS" in selectCompileOptions()
}
@RawQuery
protected abstract fun selectCompileOptions(
query: SelectCompileOptionsQuery = SelectCompileOptionsQuery
): List<String>
protected object SelectCompileOptionsQuery : SupportSQLiteQuery {
override fun getSql(): String = "PRAGMA compile_options"
override fun bindTo(statement: SupportSQLiteProgram?) = Unit
override fun getArgCount(): Int = 0
}
}
SQLITE_ENABLE_FTS3_PARENTHESIS
がコンパイルオプションとして指定されている場合に、isEnhancedQueryEnabled
がtrue
になります。
実装時のコツですが、@RawQuery
は出来ることが多いので、できるだけ使用を制限することをおすすめします。SupportSQLiteQuery
を継承した特定のクエリ専用のクラスを作り、@RawQuery
を付けた関数のデフォルト引数で渡すと良いでしょう。
サンプルコードはこちらにあります。
テーブルを動的に指定
テーブルを動的に指定するような特殊なクエリは、DAOの関数の引数をバインドすることが出来ません。@RawQuery
を使って実装できますが、このケースではRoom自体を使わないほうが良いかもしれません。
Roomが生成するコードに問題がある
Roomが生成するコードにバグが存在したり、パフォーマンスが悪い場合に@RawQuery
が役立つかもしれません。
SQLiteを暗号化するライブラリのSQLCipherとRoomを組み合わせた際に、特定のクエリでアプリがクラッシュする問題が以前あったのですが、それが解決するまでの間は@RawQuery
で実装したクエリで代用したことがあります。
おわりに
実用的な@RawQuery
の使いどころとしてはPRAGMAぐらいしか無い気がします。もし効果的に@RawQuery
を利用している方がいましたら、コメントでどう使っているかを教えてくれると嬉しいです。