我有一个安卓系统的数据库,其中有一个房间,我从中删除了一个专栏.我当时正在进行迁移,我发现这并不像删除一列那么简单.

然后我看到,我必须采取一系列步骤,创建一个临时表,该表稍后将成为具有删除列的新表,但问题是,该表包含一个字符串数组字段,我不知道如何在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
)

现在我已经删除了ingredients列.我想做这样的事情:

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

但是,当我声明新的临时表User_Backup时,我不知道如何指定其中一个字段是array.最后,我可以通过Room的自动迁移和创建一个界面来实现这一点,但我也想知道如何以这种方式实现.

推荐答案

简单的方法是使用@Database注释的实体列表中已更改的@Entity注释类编译代码(Ctrl+F9).

然后看看生成的java(通过Android Studio中的Android视图可见).将有一个与@Database注释类同名但后缀为_Impl的类.

在这个类中将有一个名为createAllTables的方法,其中包括room用于创建表的SQL.

只需复制并粘贴适当的SQL,然后更改表名,这不仅会使用正确的类型,而且会应用Room期望的正确列约束.

我建议

  1. 在创建表之前添加execSQL("DROP TABLE IF EXISTS the_backup_table_name;")(以防万一它已经存在)
  2. 而不是使用execSQL("DROP TABLE Users")来使用execSQL("DROP TABLE IF EXISTS the_original_table_name")
  • 就我个人而言,我总是重命名原始表的表名,然后重命名新表,最后删除重命名的原始表.

我会使用:-

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 .... 指示SQL是从生成的java复制的,表名从Users更改为Users_Backup
  • 第一行将删除Uers_备份,以防它碰巧存在,在异常情况下失败的可能性稍小.
  • 而不是在将Users_Backup重命名为Users之前删除Users表.第四个execSQL更改了Users表的名称,因此如果将Users_Backup表更改为Users表时出现问题,那么原始的Uers表可以作为旧用户使用.
  • 全部完成后,原始用户表(现在命名为Old_Users)将被删除.
  • 这些都只是稍微安全一点.

Android相关问答推荐

在Android的Whatsapp中共享多个图片和文本

处理Room数据库中的嵌套实体

尽管我们不再使用GCM SDK,但应用程序已被标记为使用GCM SDK

使用RecycleView和Diffutils时从列表中删除项目时出现问题

如何将 Room Persistence 依赖项正确添加到我的 Jetack Compose Android 应用程序

是否可以在 compose 中使用三次贝塞尔曲线进行动画?

Android Jetpack Compose全宽度抽屉优化

当父布局的背景为浅色时,Android ProgressBar 背景 colored颜色 变为灰色

如何从 firebase 实时数据库中检索最后一个值

延时kotlin中时分秒的使用方法

React Native Android 应用程序在调试模式下运行良好,但当我们发布 apk 时,它会生成旧版本的应用程序

Jetpack Compose Arc 进度条动画(如何重启动画)

无法为:app@debug/compileClasspath解析依赖项com.github.dhaval2404:imagepicker-support:1.7.1

Android Studio xml 预览问题无法初始化编辑器

在jetpack compose中将图像添加到脚手架顶部栏

firebase-messaging和firebase-inappmessaging-display之间有什么区别?

更新后 Firebase 服务无法在模拟器上运行

为什么按钮没有拉伸到屏幕边缘?

Jetpack compose 绘制形状

Android:在模块 jetified-play-services-measurement 和 jetified-play-services-measurement-impl 中发现重复类