【问题标题】:Android Room - How to migrate when a nested object model is changed?Android Room - 如何在更改嵌套对象模型时迁移?
【发布时间】:2019-09-29 11:52:15
【问题描述】:

我使用设置为 POJO 的 Android Room、Dao 和 Entity 类设置了数据库架构。除了 POJO 实体不是那么“简单”并且它实际上包含对另一个对象的引用。我当时认为这是一个好主意,因为它让我可以更灵活地更改对象并在应用程序的其他地方使用它,并且只根据需要保存到数据库中。

我现在面临的问题是the migration guideline只提到了如何通过更改SQL来迁移数据库,但我更改了对象本身。我的typeconverter 类只是简单地将对象转换为字符串。

因为它被保存为一个长字符串,我知道我基本上必须在SQL 中做一个简单的REPLACE(string, old_string, new_string) 更新对象为新字符串的迁移代码块。如何在迁移块中运行 replace SQL 命令之前检索旧对象并更新值?

更新:我在 typeconverter 类中使用 GSON 将对象更改为字符串,因此想到的解决方案是简单地下载旧对象并使用添加的字段。唯一的问题是您无法访问数据库并下载 json,将其转换为对象,添加新的数据字段,然后重新转换为新的 json 字符串。

我很幸运,我还没有达到规模,因为对于这么多用户来说,这将是一件棘手的事情。 (所以我建议任何阅读这篇文章的人不要像我一样执行对象嵌套。在更新要保存的数据时,将 Entry 对象转换为其他可移植对象而不是嵌套更容易。)

我认为,如果您已经做了我所做的并且无法返回,最好的办法是简单地创建新的可移植对象并为其创建新的类型转换器函数,并为新对象添加 SQL COLUMN。那么问题就在于如何从 Entry Dao 中检索这些对象,如果不仔细执行,这将导致编写更多代码并可能导致调试错误。

长话短说,如果有人正在阅读本文,请不要在 Android 上的 Room DB 中嵌套对象,除非您 100% 确定它是您模型的最终形式……但是否存在这样的事情?

【问题讨论】:

  • 我想我有一个类似的问题。我添加了一个 @Embedded 字段,它是一个对象。我无法添加正确的迁移,也找不到任何这样做的示例。我虽然只是简单地转换对象并存储为字符串,但是,你刚才描述的事情就会发生。
  • 我已经有一段时间没有想到这个了。再次阅读后,我认为需要交替类型转换器才能将空值插入新对象或修改对象类以包含“新”和“旧”版本。然后在后台从旧模式中丢失数据时包括一个获取任务。这不是一件容易的事,但在这种情况下迁移时必须避免数据丢失。未来的自我/其他开发者需要注意的是避免这个错误,并在第一个对象实例中包含尽可能多的数据。
  • 是的,我刚刚删除了嵌入对象,只是将键包含在原始对象中(反正它只有两个键)。

标签: android sql type-conversion android-room


【解决方案1】:

我刚刚遇到了这个问题,但幸运的是,我只需要在“平面”对象模型中添加一个新的 key/value 对。所以希望我的答案可以扩展为完全回答@Mr.Drew 的问题。

假设您有一个表 town,其中有一列 star_citizen 是被类型转换的对象模型:

{"name":"John", "age":30, "car":false}

并且您想更新对象以具有额外的属性"house": true

您可以像这样(Kotlin 示例)向您的应用的 Room Database 类添加迁移:

@Database(entities = [Town::class], version = 2,  exportSchema = true)
@TypeConverters(DataConverters::class)
abstract class AppDatabase : RoomDatabase() {
    abstract val sharedDao : SharedDao

    companion object {
        private val MIGRATION_1_2 = object : Migration(1, 2) {
            override fun migrate(database: SupportSQLiteDatabase) {
                val cursor = database.query("SELECT * FROM `town`")

                // iterate through each row in `town`, and update the json
                // of the StarCitizen object model
                cursor.moveToFirst()
                while (!cursor.isAfterLast) {
                    val colIdIdx = cursor.getColumnIndex("id")
                    val id = cursor.getInt(colIdIdx)

                    val colStarCitizenIdx = cursor.getColumnIndex("star_citizen")
                    val rawJson = cursor.getString(colStarCitizenIdx)

                    val updatedRawJson =  starCitizenModelV1ToV2(rawJson)

                    database.execSQL("""UPDATE town SET star_citizen ='${updatedRawJson}' WHERE ID = $id""")
                    cursor.moveToNext()
                }
            }
        }


        //[...]

        private fun starCitizenModelV1ToV2(rawJson: String): String {
            val rawJsonOpenEnded = rawJson.dropLast(1)
            val newProperty = "\"house\":true"

            return "$rawJsonOpenEnded,$newProperty}"
        }
    }
}

【讨论】:

    猜你喜欢
    • 2020-01-22
    • 2020-11-21
    • 2021-04-10
    • 1970-01-01
    • 2018-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多