如何更正错误的房间迁移?
How do I correct a wrong Room migration?
我在 table 中添加了一列,然后添加了以下迁移(版本 56 到 57):
private val MIGRATION_56_57 = object : Migration(56, 57) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE `app_stage` ADD COLUMN hasSeenBusinessOwnerQuestion INTEGER DEFAULT 0 NOT NULL")
}
}
在构建应用并将其发布给现有用户后,他们遇到迁移错误并且应用崩溃。要更正错误,我只需要更改:hasSeenBusinessOwnerQuestion INTEGER DEFAULT 0 NOT NULL
至:hasSeenBusinessOwnerQuestion INTEGER DEFAULT 0
.
我是否应该添加另一个从版本 57 到 58 的迁移:
private val MIGRATION_57_58 = object : Migration(57, 58) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE `app_stage` ADD COLUMN hasSeenBusinessOwnerQuestion INTEGER DEFAULT 0 ")
}
}
?
现有用户从版本 56 一直升级到 58 是否会遇到同样的迁移错误?如何向版本 58 添加另一个迁移以避免迁移错误?
? Will existing users upgrading from version 56 all the way to 58 get that same migration error?
否 Room 将按顺序调用所有迁移(56-57,然后是 57-58),然后在执行所有迁移后 继续数据库构建。
但是您不能使用 ALTER 命令来添加一个已经存在的列,从 57 到 58 就是这种情况。所以迁移会失败。
尽管 SQLite (3.35.0) 的更高版本支持 ALTER TABLE .... DROP COLUMN ....
,但目前此版本在 Android 设备上不可用,并且没有 ALTER COLUMN。您将不得不使用替代方法来更改该列。
- DROP COLUMN 也非常严格
您可以执行以下操作(其中 ? 表示有问题的 table):-
DROP TABLE IF EXISTS ?_old
- 这只是 in-case 它存在(不应该)
- 使用
ALTER TABLE ? RENAME TO ?_old
(_old 只是一个建议名称,用于 table 的临时版本)
- 使用
CREATE TABLE IF NOT EXISTS ....
- Room 要求创建 table SQL 根据它如何解释用 @Entity 注释的 class 创建 table。
- 建议您从编译项目后可用的生成java中检索创建tableSQL。 SQL 将在 class 的 createAllTables 方法中,它与使用 @Database 注释但后缀为 class 相同=29=]_Impl
- 使用
INSERT INTO ? SELECT * FROM ?_old
将现有数据复制到新创建的table 版本中
- 使用
DROP TABLE IF EXISTS ?
所以除了CREATE TABLE ....
(必须更改,见上面的几点)之外,以下将满足所有场景(新用户、57 上的用户)和用户 56) :-
private val MIGRATION_57_58 = object : Migration(57, 58) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS `app_stage_old`")
database.execSQL("ALTER TABLE `app_stage` RENAME TO `app_stage_old`")
/* NOTE the CREATE TABLE IF NOT EXISTS .... SHOULD BE ALTERED ACCORDINGLY */
database.execSQL("CREATE TABLE IF NOT EXISTS `app_stage` (`id` INTEGER, `name` TEXT NOT NULL,`hasSeenBusinessOwnerQuestion` INTEGER DEFAULT 0, PRIMARY KEY(`id`))")
database.execSQL("INSERT INTO `app_stage` SELECT * FROM `app_stage_old`")
database.execSQL("DROP TABLE IF EXISTS `app_stage_old`")
}
}
我在 table 中添加了一列,然后添加了以下迁移(版本 56 到 57):
private val MIGRATION_56_57 = object : Migration(56, 57) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE `app_stage` ADD COLUMN hasSeenBusinessOwnerQuestion INTEGER DEFAULT 0 NOT NULL")
}
}
在构建应用并将其发布给现有用户后,他们遇到迁移错误并且应用崩溃。要更正错误,我只需要更改:hasSeenBusinessOwnerQuestion INTEGER DEFAULT 0 NOT NULL
至:hasSeenBusinessOwnerQuestion INTEGER DEFAULT 0
.
我是否应该添加另一个从版本 57 到 58 的迁移:
private val MIGRATION_57_58 = object : Migration(57, 58) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE `app_stage` ADD COLUMN hasSeenBusinessOwnerQuestion INTEGER DEFAULT 0 ")
}
}
? 现有用户从版本 56 一直升级到 58 是否会遇到同样的迁移错误?如何向版本 58 添加另一个迁移以避免迁移错误?
? Will existing users upgrading from version 56 all the way to 58 get that same migration error?
否 Room 将按顺序调用所有迁移(56-57,然后是 57-58),然后在执行所有迁移后 继续数据库构建。
但是您不能使用 ALTER 命令来添加一个已经存在的列,从 57 到 58 就是这种情况。所以迁移会失败。
尽管 SQLite (3.35.0) 的更高版本支持 ALTER TABLE .... DROP COLUMN ....
,但目前此版本在 Android 设备上不可用,并且没有 ALTER COLUMN。您将不得不使用替代方法来更改该列。
- DROP COLUMN 也非常严格
您可以执行以下操作(其中 ? 表示有问题的 table):-
DROP TABLE IF EXISTS ?_old
- 这只是 in-case 它存在(不应该)
- 使用
ALTER TABLE ? RENAME TO ?_old
(_old 只是一个建议名称,用于 table 的临时版本) - 使用
CREATE TABLE IF NOT EXISTS ....
- Room 要求创建 table SQL 根据它如何解释用 @Entity 注释的 class 创建 table。
- 建议您从编译项目后可用的生成java中检索创建tableSQL。 SQL 将在 class 的 createAllTables 方法中,它与使用 @Database 注释但后缀为 class 相同=29=]_Impl
- 使用
INSERT INTO ? SELECT * FROM ?_old
将现有数据复制到新创建的table 版本中
- 使用
DROP TABLE IF EXISTS ?
所以除了CREATE TABLE ....
(必须更改,见上面的几点)之外,以下将满足所有场景(新用户、57 上的用户)和用户 56) :-
private val MIGRATION_57_58 = object : Migration(57, 58) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS `app_stage_old`")
database.execSQL("ALTER TABLE `app_stage` RENAME TO `app_stage_old`")
/* NOTE the CREATE TABLE IF NOT EXISTS .... SHOULD BE ALTERED ACCORDINGLY */
database.execSQL("CREATE TABLE IF NOT EXISTS `app_stage` (`id` INTEGER, `name` TEXT NOT NULL,`hasSeenBusinessOwnerQuestion` INTEGER DEFAULT 0, PRIMARY KEY(`id`))")
database.execSQL("INSERT INTO `app_stage` SELECT * FROM `app_stage_old`")
database.execSQL("DROP TABLE IF EXISTS `app_stage_old`")
}
}