Room の 2.3.0 から RewriteQueriesToDropUnusedColumns というアノテーションが追加されていたので、こちらについて調べてみました。
Room では以下のように Dao で @Query
メソッドを定義することによって、データベースからデータが取得できます。
以下はユーザーのデータを取得する例です。
@Entity(tableName = "users")
data class User(
@PrimaryKey val id: Int,
val name: String,
val age: Int,
val gender: Gender,
val address: String
)
@Dao
interface UserDao {
@Query("SELECT * FROM users")
fun getUsers(): List<User>
}
この時、例えばユーザーの名前と年齢だけあればよいのであれば、以下のように書くこともできます。
data class UserNameAndAge(val name: String, val age: Int)
@Dao
interface UserDao {
@Query("SELECT * FROM users")
fun getUsers(): List<UserNameAndAge> // 戻り値を List<User> から List<UserNameAndAge> に変更
}
ただ、この状態でビルドを実行すると、コンパイラが以下のような警告を出力します。
warning: The query returns some columns [id, address, gender] which are not used by UserNameAndAge.
クエリでは id
, address
, gender
のカラムを返しているのに、UserNameAndAge
では使われていないと警告しています。
続けて警告を読んでいくと、以下のような文が出力されています。
You can annotate the method with @RewriteQueriesToDropUnusedColumns to direct Room to rewrite your query to avoid fetching unused columns.
どうやらメソッドに @RewriteQueriesToDropUnusedColumns
アノテーションを付けると、Room は不必要なカラムを取得しないようにクエリを書き換えてくれるようです。
まずはこのアノテーションが付いていない状態でコンパイルした際に生成される UserDao_Impl.java
を見ると以下のようにコードが生成されていました。
@Override
public List<UserNameAndAge> getUsers() {
final String _sql = "SELECT * FROM users";
...
}
次に、以下のようにアノテーションを付与してコンパイルしてみます。
@Dao
interface UserDao {
@RewriteQueriesToDropUnusedColumns
@Query("SELECT * FROM users")
fun getUsers(): List<UserNameAndAge>
}
この状態でコンパイルして生成された UserDao_Impl.java
は以下です。
@Override
public List<UserNameAndAge> getUsers() {
final String _sql = "SELECT `name`, `age` FROM (SELECT * FROM users)";
...
}
確かにクエリが書き換えられているようです。
ドキュメント を読む限りだと、このクエリは Sqlite 側では SELECT name, age FROM users
と変更してくれるようです。
また、@RewriteQueriesToDropUnusedColumns
アノテーションはメソッドだけではなく @Dao
のインターフェース(もしくはクラス)や @Database
のクラスにも付与することができ、適用する範囲を Dao 単位や Database 単位にすることもできるようです。