Android Roomの自動マイグレーション
AndroidにRoomというSQLiteのライブラリがありますが、マイグレーションに関してはサポートが薄く単純な変更ですらコストがかかっていると思います。
という状況だったのですが、 2.4.0-alpha01
にて一部の変更の自動マイグレーションがサポートされたようです 🎉🎉
全自動でマイグレーションされる場合
明文化はされていないようですが、以下の場合は全自動でマイグレーションされるようです。
- テーブルの追加
- カラムの追加
スキーマをエクスポートするように設定した後、以下のように Database
アノテーションに変更バージョン情報を持った AutoMigration
を指定してあげるだけです。
@Database( entities = [Todo::class], version = 2, autoMigrations = [ AutoMigration(from = 1, to = 2) ] ) abstract class AppDatabase : RoomDatabase() { abstract fun todoDao(): TodoDao }
サポートが必要な場合
Roomのコードを少し読んでみると、SchemaDiffer クラス でスキーマのdiffを取り、AutoMigrationProcessor クラス ではその追加されたテーブル/カラム情報は利用していますが削除された情報は利用していません。
これはテーブル/カラムが削除されていた場合、それが単なる削除なのかリネームなのかが判定できないからです。
ということで、以下の変更は AutoMigrationSpec を実装してどう変わったかをRoomに教えてあげる必要があります。
- テーブル名の変更 (
@RenameTable(fromName, toName)
) - テーブルの削除 (
@DeleteTable(name)
) - カラム名の変更 (
@RenameColumn(tableName, fromColName, toColName)
) - カラムの削除 (
@DeleteColumn(tableName, colName)
)
上記変更が必要な場合は、生SQLを書いてねというわけではなくしっかりサポートがあるあたり優しいですね。
また、試してみたところspecの指定が不足していた場合コンパイル時に何が必要か優しく教えてくれます。
error: public abstract class AppDatabase extends androidx.room.RoomDatabase { ^ AutoMigration Failure: Please declare an interface extending 'AutoMigrationSpec', and annotate with the @RenameColumn or @RemoveColumn annotation to specify the change to be performed: 1) RENAME: @RenameColumn( tableName = "Todo", originalColumnName = "isDone", newColumnName = <NEW_COLUMN_NAME> ) 2) DELETE: @DeleteColumn=( tableName = "Todo", deletedColumnName = "isDone" )
複数変更がある場合は以下のように指定してあげれば良いです。
@DeleteColumn( tableName = "Todo", columnName = "isDone" ) @RenameColumn( tableName = "Todo", fromColumnName = "text", toColumnName = "content" ) class V3AutoMigrationSpec : AutoMigrationSpec
生SQLが必要な場合
それ以外の複雑なテーブルの変更は生SQLでマイグレーションを書いてあげる必要があります。 例えば以下のような場合です。
- テーブルを分割/統合する
- テーブルの正規化/非正規化
- Viewに対する変更
Viewは試してみた限り、今回のサポートには入っていないようです。(多分)
生SQLが必要な場合でも、AutoMigration機能と併用することができます。
まとめ
まだ現時点ではalpha版なのでそこは注意ですが、かなりマイグレーションの負担が減るのではないでしょうか。
個人的にはかなり嬉しいアップデートでした。