简体   繁体   English

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

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

I have a database in Android with Room from which I have deleted a column.我在 Android 中有一个带有 Room 的数据库,我从中删除了一个列。 I was doing the migration, and I saw that it was not as simple as doing a DROP of the deleted column.我正在做迁移,我发现它并不像对已删除的列进行 DROP 那样简单。

Then I have seen that I have to take a series of steps, creating a provisional table that will later be the new table with the deleted column, but the problem is that this table contains a field that is a String Array that I don't know how to declare in SQL.然后我看到我必须采取一系列步骤,创建一个临时表,该表稍后将成为具有已删除列的新表,但问题是该表包含一个我不包含的字符串数组字段知道如何在 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
)

And now I have removed the ingredients column.现在我已经删除了ingredients列。 I wanted to do something like this:我想做这样的事情:

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")
            }
        }
    }

But when I declare the new temporary table User_Backup, I have no idea how to specify that one of the fields is an Array.但是当我声明新的临时表 User_Backup 时,我不知道如何指定其中一个字段是数组。 In the end I was able to do it with Room's AutoMigrations and creating an interface, but I would like to know how to do it this way as well.最后,我能够使用 Room 的 AutoMigrations 并创建一个界面来做到这一点,但我也想知道如何做到这一点。

The simple way is to compile the code (Ctrl+F9) with the changed @Entity annotated classes in the list of entities of the @Database annotation.简单的方法是使用@Database 注释的实体列表中更改的@Entity 注释类来编译代码(Ctrl+F9)。

Then look at the generated java (visible via the Android View in Android Studio).然后查看生成的 java(通过 Android Studio 中的 Android View 可见)。 There will be a class that is the same name as the @Database annotated class but suffixed with _Impl .将有一个与 @Database 注释类同名但后缀为_Impl的类。

In this class there will be a method that is named createAllTables , This includes the SQL that room uses for creating the tables.在此类中,将有一个名为createAllTables的方法,其中包括 room 用于创建表的 SQL。

Just copy and paste the appropriate SQL and then change the table name, this will not only use the correct type but also apply the correct column constraints that Room expects.只需复制并粘贴适当的 SQL,然后更改表名,这不仅会使用正确的类型,还会应用 Room 期望的正确列约束。

I would suggest我会建议

  1. Adding an execSQL("DROP TABLE IF EXISTS the_backup_table_name;") before you create a table (just in case it already exists)在创建表之前添加execSQL("DROP TABLE IF EXISTS the_backup_table_name;") (以防万一它已经存在)
  2. And instead of using execSQL("DROP TABLE Users") to use execSQL("DROP TABLE IF EXISTS the_original_table_name")而不是使用execSQL("DROP TABLE Users")来使用execSQL("DROP TABLE IF EXISTS the_original_table_name")
  • Personally I always RENAME the table name of the original, then RENAME the new table and then finally DROP the renamed original.就个人而言,我总是重命名原始表名,然后重命名新表,最后 DROP 重命名的原始表。

I would use:-我会使用:-

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 .... indicates that the SQL is copied from the generated java and that the table name is changed from Users to Users_Backup note ....表示从生成的java复制SQL,表名由Users改为Users_Backup
  • The first line will drop the Uers_backup just in case it happens to exist, it's just a little less likely to fail under unusual circumstances.第一行将删除 Uers_backup 以防万一它碰巧存在,在异常情况下失败的可能性要小一些。
  • Rather than dropping the Users table before the RENAME of the Users_Backup to Users .而不是在将Users_Backup 重命名Users之前删除Users表。 The 4th execSQL changes the name of the Users table, so should there be an issue with changing the Users_Backup table to be the Users table, then the original Uers table is available as Old_users.第 4 个 execSQL 更改了Users表的名称,因此如果将Users_Backup表更改为Users表时出现问题,则原始 Uers 表可作为 Old_users 使用。
  • When all has been complted then the original Users table, now named Old_Users is then dropped.完成所有操作后,将删除现在名为 Old_Users 的原始用户表。
  • These are all just a little safer/secure.这些都只是更安全/安全一点。

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

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