Android Architecture Component Room永続化データベース(5)Roomデータベースの移行


本文はブロガーのオリジナルの文章で、みんなが転載することを歓迎します!
ただし転載は出典を明記してください.https://blog.csdn.net/t000818/article/details/84303795,本文出典:【唐宏宇のブログ】
アプリケーションで機能を追加および変更する場合は、データベース・エンティティ・クラスを変更して変更をマッピングする必要があります.ユーザーが最新バージョンのアプリケーションに更新した場合、特にリモート・サーバからデータをリカバリできない場合は、既存のすべてのデータを失うことを望んでいません.
Room persistence libraryライブラリは、Migrationクラスを作成してユーザーデータを保持できます.各MigrationクラスはstartVersionとendVersionを指定します.実行時、Roomは各Migrationクラスのmigrate()メソッドを実行し、正しい順序でデータベースをより高いバージョンに移行します.
Kotlin表記:
val MIGRATION_1_2 = object : Migration(1, 2) {
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL("CREATE TABLE `Fruit` (`id` INTEGER, `name` TEXT, " +
                "PRIMARY KEY(`id`))")
    }
}

val MIGRATION_2_3 = object : Migration(2, 3) {
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL("ALTER TABLE Book ADD COLUMN pub_year INTEGER")
    }
}

Room.databaseBuilder(applicationContext, MyDb::class.java, "database-name")
        .addMigrations(MIGRATION_1_2, MIGRATION_2_3).build()

Java書き方:
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        database.execSQL("CREATE TABLE `Fruit` (`id` INTEGER, "
                + "`name` TEXT, PRIMARY KEY(`id`))");
    }
};

static final Migration MIGRATION_2_3 = new Migration(2, 3) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        database.execSQL("ALTER TABLE Book "
                + " ADD COLUMN pub_year INTEGER");
    }
};

Room.databaseBuilder(getApplicationContext(), MyDb.class, "database-name")
        .addMigrations(MIGRATION_1_2, MIGRATION_2_3).build();

警告:移行ロジックを予想通りに実行するには、クエリーの定数を参照するのではなく、完全なクエリーを使用します.
移行プロセスが完了すると、Roomはモデルを検証し、移行が正しく行われていることを確認します.Roomが問題を発見すると、不一致情報を含む例外が放出されます.
 
データ移行のテスト
移行は容易ではありませんが、正しく作成されていないとアプリケーションがクラッシュする可能性があります.アプリケーションの安定性を維持するには、事前に移行をテストする必要があります.Roomは、このテストプロセスを支援するためのテストMaven依存ライブラリを提供します.ただし、この依存ライブラリを有効にするには、データベースのモデルをエクスポートする必要があります.
 
モデルのエクスポート
コンパイル時、Roomはデータベースのモデル情報をJSONファイルにエクスポートします.スキーマをエクスポートするにはbuild.gradleファイルでroomを設定します.schemaLocationデプロセッサのプロパティは、次のコード・セグメントに示されています.
build.gradle
android {
    ...
    defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = ["room.schemaLocation":
                             "$projectDir/schemas".toString()]
            }
        }
    }
}

テストパッケージにはMigrationTestHelperクラスがあり、これらのモデルファイルを読み込むことができます.JUnit 4 TestRuleインタフェースも実装されているため、作成したデータベースを管理できます.
次のコード・セグメントには、移行テストの例が表示されます.
Kotlin表記:
@RunWith(AndroidJUnit4::class)
class MigrationTest {
    private val TEST_DB = "migration-test"

    @Rule
    val helper: MigrationTestHelper = MigrationTestHelper(
            InstrumentationRegistry.getInstrumentation(),
            MigrationDb::class.java.canonicalName,
            FrameworkSQLiteOpenHelperFactory()
    )

    @Test
    @Throws(IOException::class)
    fun migrate1To2() {
        var db = helper.createDatabase(TEST_DB, 1).apply {
            // db has schema version 1. insert some data using SQL queries.
            // You cannot use DAO classes because they expect the latest schema.
            execSQL(...)

            // Prepare for the next version.
            close()
        }

        // Re-open the database with version 2 and provide
        // MIGRATION_1_2 as the migration process.
        db = helper.runMigrationsAndValidate(TEST_DB, 2, true, MIGRATION_1_2)

        // MigrationTestHelper automatically verifies the schema changes,
        // but you need to validate that the data was migrated properly.
    }
}

Java書き方:
@RunWith(AndroidJUnit4.class)
public class MigrationTest {
    private static final String TEST_DB = "migration-test";

    @Rule
    public MigrationTestHelper helper;

    public MigrationTest() {
        helper = new MigrationTestHelper(InstrumentationRegistry.getInstrumentation(),
                MigrationDb.class.getCanonicalName(),
                new FrameworkSQLiteOpenHelperFactory());
    }

    @Test
    public void migrate1To2() throws IOException {
        SupportSQLiteDatabase db = helper.createDatabase(TEST_DB, 1);

        // db has schema version 1. insert some data using SQL queries.
        // You cannot use DAO classes because they expect the latest schema.
        db.execSQL(...);

        // Prepare for the next version.
        db.close();

        // Re-open the database with version 2 and provide
        // MIGRATION_1_2 as the migration process.
        db = helper.runMigrationsAndValidate(TEST_DB, 2, true, MIGRATION_1_2);

        // MigrationTestHelper automatically verifies the schema changes,
        // but you need to validate that the data was migrated properly.
    }
}

 
失われた移行経路を優雅に処理
データベースのモデルを更新しても、一部のデバイスのデータベースでは古いモードバージョンが使用される場合があります.Roomがデバイスのデータベースを古いバージョンから現在のバージョンにアップグレードする移行ルールが見つからない場合、IllegalStateExceptionが発生します.
このような状況でアプリケーションがクラッシュしないようにするには、データベースの作成時にfallbackToDestructiveMigration()ビルダーメソッドを呼び出します.
Kotlin表記:
Room.databaseBuilder(applicationContext, MyDb::class.java, "database-name")
        .fallbackToDestructiveMigration()
        .build()

Java書き方:
Room.databaseBuilder(getApplicationContext(), MyDb.class, "database-name")
        .fallbackToDestructiveMigration()
        .build();

アプリケーションのデータベース構築ロジックにこの句を追加することで、Roomがデータベース・モデルのバージョン間の移行パスが欠けている場合に、アプリケーションのデータベース・テーブルを破壊的に再作成することを通知できます.
警告:このオプションをアプリケーションのデータベース・ビルダーで構成すると、Roomは移行パスが見つからないときにデータベース・テーブルのすべてのデータを永続的に削除します.破壊的なロールバックロジックには、いくつかの追加オプションがあります.
  • 移行パスを使用して解決できないアーキテクチャ履歴の特定のバージョンでエラーが発生した場合は、fallbackToDestructiveMigrationFrom()を使用します.この方法は、データベースが問題のあるバージョンから移行しようとした場合にのみ、Roomにロールバックロジックを使用することを意味します.
  • 試行モード降格時のみ破壊再作成を実行するには、fallbackToDestructiveMigrationOnDowngrade()
  • に変更します.