如何更正错误的房间迁移?

How do I correct a wrong Room migration?

我在 table 中添加了一列,然后添加了以下迁移(版本 56 到 57):

private val MIGRATION_56_57 = object : Migration(56, 57) {
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL("ALTER TABLE `app_stage` ADD COLUMN hasSeenBusinessOwnerQuestion INTEGER DEFAULT 0 NOT NULL")
    }
}

在构建应用并将其发布给现有用户后,他们遇到迁移错误并且应用崩溃。要更正错误,我只需要更改:hasSeenBusinessOwnerQuestion INTEGER DEFAULT 0 NOT NULL 至:hasSeenBusinessOwnerQuestion INTEGER DEFAULT 0 .

我是否应该添加另一个从版本 57 到 58 的迁移:

 private val MIGRATION_57_58 = object : Migration(57, 58) {
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL("ALTER TABLE `app_stage` ADD COLUMN hasSeenBusinessOwnerQuestion INTEGER DEFAULT 0 ")
    }
}

? 现有用户从版本 56 一直升级到 58 是否会遇到同样的迁移错误?如何向版本 58 添加另一个迁移以避免迁移错误?

? Will existing users upgrading from version 56 all the way to 58 get that same migration error?

Room 将按顺序调用所有迁移(56-57,然后是 57-58),然后在执行所有迁移后 继续数据库构建。

但是您不能使用 ALTER 命令来添加一个已经存在的列,从 57 到 58 就是这种情况。所以迁移会失败。

尽管 SQLite (3.35.0) 的更高版本支持 ALTER TABLE .... DROP COLUMN ....,但目前此版本在 Android 设备上不可用,并且没有 ALTER COLUMN。您将不得不使用替代方法来更改该列。

  • DROP COLUMN 也非常严格

您可以执行以下操作(其中 ? 表示有问题的 table):-

  1. DROP TABLE IF EXISTS ?_old
    1. 这只是 in-case 它存在(不应该)
  2. 使用 ALTER TABLE ? RENAME TO ?_old(_old 只是一个建议名称,用于 table 的临时版本)
  3. 使用CREATE TABLE IF NOT EXISTS ....
    1. Room 要求创建 table SQL 根据它如何解释用 @Entity 注释的 class 创建 table。
    2. 建议您从编译项目后可用的生成java中检索创建tableSQL。 SQL 将在 class 的 createAllTables 方法中,它与使用 @Database 注释但后缀为 class 相同=29=]_Impl
  4. 使用INSERT INTO ? SELECT * FROM ?_old将现有数据复制到新创建的table
  5. 版本中
  6. 使用DROP TABLE IF EXISTS ?

所以除了CREATE TABLE ....(必须更改,见上面的几点)之外,以下将满足所有场景(新用户、57 上的用户)和用户 56) :-

    private val MIGRATION_57_58 = object : Migration(57, 58) {
        override fun migrate(database: SupportSQLiteDatabase) {
            database.execSQL("DROP TABLE IF EXISTS `app_stage_old`")
            database.execSQL("ALTER TABLE `app_stage` RENAME TO `app_stage_old`")
            /* NOTE the CREATE TABLE IF NOT EXISTS .... SHOULD BE ALTERED ACCORDINGLY */
            database.execSQL("CREATE TABLE IF NOT EXISTS `app_stage` (`id` INTEGER, `name` TEXT NOT NULL,`hasSeenBusinessOwnerQuestion` INTEGER DEFAULT 0, PRIMARY KEY(`id`))")
            database.execSQL("INSERT INTO `app_stage` SELECT * FROM `app_stage_old`")
            database.execSQL("DROP TABLE IF EXISTS `app_stage_old`")
        }
    }