繁体   English   中英

使用 Android 字符串数组在 Room 中迁移

[英]Migration in Room with an Android Array of Strings

我在 Android 中有一个带有 Room 的数据库,我从中删除了一个列。 我正在做迁移,我发现它并不像对已删除的列进行 DROP 那样简单。

然后我看到我必须采取一系列步骤,创建一个临时表,该表稍后将成为具有已删除列的新表,但问题是该表包含一个我不包含的字符串数组字段知道如何在 SQL 中声明。

@Entity(tableName = "recipe_table")
data class RecipesDb(
    @PrimaryKey
    @ColumnInfo(name = "id")
    val id: Long,
    @ColumnInfo(name = "name")
    val name: String,
    @ColumnInfo(name = "category")
    val category: List<String>,
    @ColumnInfo(name = "isRecommended")
    val isRecommended: Boolean,
    @ColumnInfo(name = "images")
    val images: List<String>,
    @ColumnInfo(name = "ingredients")
    val ingredients: List<String>,
    @ColumnInfo(name = "date")
    val date: Long,
    @ColumnInfo(name = "time")
    val time: Int,
    @ColumnInfo(name = "difficult")
    val difficult: String,
    @ColumnInfo(name = "originalUrl")
    val originalURL: String? = null,
    @ColumnInfo(name = "author")
    val author: String,
    @ColumnInfo(name = "siteName")
    val siteName: String
)

现在我已经删除了ingredients列。 我想做这样的事情:

private val MIGRATION_3_2 = object : Migration(3,2) {
        override fun migrate(database: SupportSQLiteDatabase) {
            //Drop column isn't supported by SQLite, so the data must manually be moved
            with(database) {
                execSQL("CREATE TABLE Users_Backup (id INTEGER, name TEXT, PRIMARY KEY (id))")
                execSQL("INSERT INTO Users_Backup SELECT id, name FROM Users")
                execSQL("DROP TABLE Users")
                execSQL("ALTER TABLE Users_Backup RENAME to Users")
            }
        }
    }

但是当我声明新的临时表 User_Backup 时,我不知道如何指定其中一个字段是数组。 最后,我能够使用 Room 的 AutoMigrations 并创建一个界面来做到这一点,但我也想知道如何做到这一点。

简单的方法是使用@Database 注释的实体列表中更改的@Entity 注释类来编译代码(Ctrl+F9)。

然后查看生成的 java(通过 Android Studio 中的 Android View 可见)。 将有一个与 @Database 注释类同名但后缀为_Impl的类。

在此类中,将有一个名为createAllTables的方法,其中包括 room 用于创建表的 SQL。

只需复制并粘贴适当的 SQL,然后更改表名,这不仅会使用正确的类型,还会应用 Room 期望的正确列约束。

我会建议

  1. 在创建表之前添加execSQL("DROP TABLE IF EXISTS the_backup_table_name;") (以防万一它已经存在)
  2. 而不是使用execSQL("DROP TABLE Users")来使用execSQL("DROP TABLE IF EXISTS the_original_table_name")
  • 就个人而言,我总是重命名原始表名,然后重命名新表,最后 DROP 重命名的原始表。

我会使用:-

private val MIGRATION_3_2 = object : Migration(3,2) {
    override fun migrate(database: SupportSQLiteDatabase) {
        //Drop column isn't supported by SQLite, so the data must manually be moved
        with(database) {
            execSQL("DROP TABLE IF EXISTS Users_Backup")
            execSQL("CREATE TABLE IF NOT EXISTS ....) //<<<<< SEE NOTES BELOW, the SQL MUST BE CHANGED.
            execSQL("INSERT INTO Users_Backup SELECT id, name FROM Users")
            execSQL("ALTER TABLE Users RENAME TO Old_Users")
            execSQL("ALTER TABLE Users_Backup RENAME to Users")
            execSQL("DROP TABLE IF EXISTS Old_users")
        }
    }
}
  • note ....表示从生成的java复制SQL,表名由Users改为Users_Backup
  • 第一行将删除 Uers_backup 以防万一它碰巧存在,在异常情况下失败的可能性要小一些。
  • 而不是在将Users_Backup 重命名Users之前删除Users表。 第 4 个 execSQL 更改了Users表的名称,因此如果将Users_Backup表更改为Users表时出现问题,则原始 Uers 表可作为 Old_users 使用。
  • 完成所有操作后,将删除现在名为 Old_Users 的原始用户表。
  • 这些都只是更安全/安全一点。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM