Android Room - 嵌套对象模型更改时如何迁移?

标签 android sql type-conversion android-room

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

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

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

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

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

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

长话短说,如果有人正在阅读这篇文章,请不要在 Android 上的 Room DB 中嵌套对象,除非您 100% 确定它是您模型的最终形式……但到底有没有这样的东西?

最佳答案

我刚遇到这个问题,还好我只需要添加一个新的key/value与“平面”对象模型配对。所以希望我的答案可以扩展到完全回答@Mr.Drew 的问题。
假设你有一张 table town有一个列 star_citizen那就是被类型转换的对象模型:{"name":"John", "age":30, "car":false}并且您想更新对象以具有额外的属性 "house": true您可以像这样(Kotlin 示例)向您的 App 的 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}"
        }
    }
}

关于Android Room - 嵌套对象模型更改时如何迁移?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56096770/

相关文章:

android - sqlite 表中始终返回 null 值

android - l 预览 : Call requires API level 21 (current min is 20)

mysql - 选择唯一字段,但不确定 DISTINCT 或 GROUP BY 是否能满足我的需要

java - 如何将多个xml值存储到java中

sql - 在 SQL 查询中将日期舍入到日期

java - 在java中将SUBSTRING转换为整数的最佳方法

android-alertdialog - 关闭来 self 的应用程序外部的对话框

Java AES 解密导致 BadPaddingException

java - 如何将 C# 字符串转换为 Java.Lang.String?

c - 如何将有符号整数转换为C中相应的无符号整数?