如何放弃手动 Room 迁移脚本,退回到破坏性迁移?
How to abandon a manual Room migration script, and fall back to destructive migration?
在我正在开发的应用程序中,我们进行了复杂的手动迁移,需要数据解析、手动 SQL 命令等。这是为了将 List<X>
列转换为新的链接table 个 X
。我已经 previously written 了解该方法,但具体命令与这个问题不是特别相关。
我遇到的问题是大约 1% 的用户在此迁移过程中遇到崩溃。这无法在测试中重现,并且由于我们 table 的大小,Crashlytics 无法显示任何有用的错误:
在这种情况下,丢失客户数据并不是灾难性的,但陷入当前的“尝试迁移、崩溃、重新打开应用程序并重复”循环才是。因此,如果我们遇到异常,我只想放弃迁移并回退到破坏性迁移。
知道如何做到这一点吗?我当前的解决方案是在 catch
中重新运行数据库更改(但不是可能失败的数据迁移),但这感觉很糟糕。
我们的数据库定义为:
Room.databaseBuilder(
context.applicationContext,
CreationDatabase::class.java,
"creation_database"
)
.addMigrations(MIGRATION_11_12, MIGRATION_14_15)
.fallbackToDestructiveMigration()
.build()
其中 MIGRATION_14_15
是:
private val MIGRATION_14_15 = object : Migration(14, 15) {
override fun migrate(database: SupportSQLiteDatabase) {
try {
// database.execSQL create table etc
} catch (e: Exception) {
e.printStackTrace()
// Here is where I want to give up, and start the DB from scratch
}
}
}
您遇到的问题是您不能(至少很容易)调用 fall-back,因为它仅在没有迁移时调用。
您可以做的是模仿 fall back 的作用(非常接近它的作用)。那就是 fall-back 将删除(我认为)数据库文件并从头开始创建数据库,然后调用数据库 _Impl(生成 java)createAllTables 方法。
但是,如果您删除文件,因为数据库连接已传递给迁移,您可能会遇到问题。
因此,您可以使用从生成的 java 中的 dropAllTables
方法复制的代码来删除应用程序的所有表。然后,您可以使用 createAllTables
方法中的代码来执行此操作。
- 这些方法在生成的java中作为class与@Database注解后缀为_Impl的class相同class
gotcha,就是那个异常
(Expected .... Found ....) 您显示的不在迁移中,而是在 Room 尝试构建数据库时迁移之后,因此您没有 control/place 要做以上 fall-back 模仿,除非对所有 14-15 次迁移都这样做。
也许您可以捕获异常,显示一个对话框,要求用户卸载应用程序,然后 re-install。这将绕过迁移,因为它将是全新安装。
在我正在开发的应用程序中,我们进行了复杂的手动迁移,需要数据解析、手动 SQL 命令等。这是为了将 List<X>
列转换为新的链接table 个 X
。我已经 previously written 了解该方法,但具体命令与这个问题不是特别相关。
我遇到的问题是大约 1% 的用户在此迁移过程中遇到崩溃。这无法在测试中重现,并且由于我们 table 的大小,Crashlytics 无法显示任何有用的错误:
在这种情况下,丢失客户数据并不是灾难性的,但陷入当前的“尝试迁移、崩溃、重新打开应用程序并重复”循环才是。因此,如果我们遇到异常,我只想放弃迁移并回退到破坏性迁移。
知道如何做到这一点吗?我当前的解决方案是在 catch
中重新运行数据库更改(但不是可能失败的数据迁移),但这感觉很糟糕。
我们的数据库定义为:
Room.databaseBuilder(
context.applicationContext,
CreationDatabase::class.java,
"creation_database"
)
.addMigrations(MIGRATION_11_12, MIGRATION_14_15)
.fallbackToDestructiveMigration()
.build()
其中 MIGRATION_14_15
是:
private val MIGRATION_14_15 = object : Migration(14, 15) {
override fun migrate(database: SupportSQLiteDatabase) {
try {
// database.execSQL create table etc
} catch (e: Exception) {
e.printStackTrace()
// Here is where I want to give up, and start the DB from scratch
}
}
}
您遇到的问题是您不能(至少很容易)调用 fall-back,因为它仅在没有迁移时调用。
您可以做的是模仿 fall back 的作用(非常接近它的作用)。那就是 fall-back 将删除(我认为)数据库文件并从头开始创建数据库,然后调用数据库 _Impl(生成 java)createAllTables 方法。
但是,如果您删除文件,因为数据库连接已传递给迁移,您可能会遇到问题。
因此,您可以使用从生成的 java 中的 dropAllTables
方法复制的代码来删除应用程序的所有表。然后,您可以使用 createAllTables
方法中的代码来执行此操作。
- 这些方法在生成的java中作为class与@Database注解后缀为_Impl的class相同class
gotcha,就是那个异常
(Expected .... Found ....) 您显示的不在迁移中,而是在 Room 尝试构建数据库时迁移之后,因此您没有 control/place 要做以上 fall-back 模仿,除非对所有 14-15 次迁移都这样做。
也许您可以捕获异常,显示一个对话框,要求用户卸载应用程序,然后 re-install。这将绕过迁移,因为它将是全新安装。