如何通过更改现有数据类型来执行 Android Room 数据库迁移?

问题描述 投票:0回答:1

我在 Android 应用程序中使用房间数据库,它提供了

Car
的表格,如下所示:

@Entity(tableName = "Cars")
data class Car(
    @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "Id") val id: Int? = null,
    @ColumnInfo(name = "Manufacture") var manufacture: String? = null, 
    @ColumnInfo(name = "Model") var model: String? = null,
    @ColumnInfo(name = "Date_created") val dateCreated: String? = null,
    @ColumnInfo(name = "Date_modified") var dateModified: String? = null,
    @ColumnInfo(name = "Color") var color: String? = null,
    @ColumnInfo(name = "Tags") var tags: String? = null
)

现在我需要对该表执行一些更改并升级它,如下所示: 现在我需要在表中应用一些更改:

@Entity(tableName = "Cars")
data class Car(
    @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "Id") var id: Long = 0,
    @ColumnInfo(name = "Manufacture") var manufacture: String = "", 
    @ColumnInfo(name = "Model") var model: String = "",
    @ColumnInfo(name = "Labels") var labels: List<String> = listOf(),
    @ColumnInfo(name = "Color") var color: String? = null,
    @ColumnInfo(name = "Timestamp") var timestamp: Long = 0L,
    @ColumnInfo(name = "Type") var type: Type = Type.Sedan,
    @ColumnInfo(name = "Folder") var folder: Folder = Folder.Used
)

此次升级对现有表格带来以下变化:

  • Id
    val id: Int? = null
    更改为
    val id: Long = 0
  • Manufacture
    var manufacture: String? = null
    更改为
    var manufacture: String = ""
  • Date_created
    var dateCreated: String? = null
    已被删除。
  • Date_modified
    重命名为
    Timestamp
    ,其数据类型也从可空
    String
    更改为不可空
    Long
    。迁移时是否可以将 String 转换为 Long ?这些字符串值是转换为字符串的时间戳 -
    timestampe.toString()
  • 数据类型
  • Tags
    var tags: String? = null
    列(用逗号分隔的一个字符串中的标签:例如
    "Gas,Diesel,Oil"
    )更改为列表
    var labels: List<String> = listOf()
    的标签。迁移时是否可以将标签字符串转换为List?
  • Type
    Folder
    是数据类型为
    enum
    的新列。

我正在向某些数据类型提出问题,必须将其更改为另一种数据类型,因为我找不到该主题的任何信息。尽管如此,我还是基于迁移 Room 数据库了解 Room 迁移做了一个小解决方法,但不确定语法和数据类型转换:

@Database(entities = [Car::class], version = 2, exportSchema = false)
abstract class CarsDatabase : RoomDatabase() {

    abstract val carDao: CarDao

    companion object {

        @Volatile
        private var INSTANCE: CarsDatabase? = null

        private val migration = object : Migration(1, 2) {
            override fun migrate(database: SupportSQLiteDatabase) {
                database.apply {
                    execSQL(
                        "CREATE TABLE cars_tmp (" +
                                "Id INTEGER, " +
                                "Manufacture TEXT, " +
                                "Model TEXT, " +
                                "Timestamp LONG, " + // Not sure about syntax for Long
                                "Labels LIST," + // Not sure about syntax for List<String>
                                "PRIMARY KEY(Id)" +
                                ")"
                    )
                    execSQL("INSERT INTO cars_tmp (" +
                            "Id, Manufacture, Model, Timestamp, Labels, Color) SELECT " +
                            "Id, Manufacture, Model, Date_modified, Tags, Color" + // String of "Date_modified" being converted to Long of "Timestamp" and String of "Tags" being converted to List<String>
                            "FROM Cars"
                    )
                    execSQL("DROP TABLE Car")
                    execSQL("ALTER TABLE cars_tmp RENAME TO Car")
                    execSQL("ALTER TABLE Car ADD COLUMN Type TEXT")
                    execSQL("ALTER TABLE Car ADD COLUMN Folder TEXT")
                }
            }
        }
        
        fun getInstance(context: Context): CarsDatabase = INSTANCE ?: synchronized(this) {
            val instance = Room.databaseBuilder(
                context.applicationContext,
                CarsDatabase::class.java,
                "Cars.db"
            )
                .addMigrations(migration)
                .build()
            INSTANCE = instance
            return instance
        }
    }
}

我并不指望有人会做我的工作,但至少我确实需要一些问题的答案才能顺利完成迁移。我对 SQL 语法还很陌生,因此我的迁移代码是错误的。

非常感谢任何帮助。

编辑: 答案可以在这里找到:如何在 os 版本 >= 26 sdk 上正确获取 Room 数据库的路径?

kotlin android-sqlite android-room database-migration
1个回答
1
投票

假设您正在进行更改并需要保留数据(如果您不需要保留任何数据,则只需进行更改并卸载应用程序即可)。

无需锻炼/猜测 Room 期望什么的最简单方法是使用 Room 生成的 SQL。

  1. 首先对表进行更改,即
    @Entity
    带注释的类。
  2. 项目编译成功。
  3. 在 Android 视图中,您将在 Android Studio 的项目资源管理器中看到,将有一个 java(生成的)展开它,直到找到与
    @Database
    注解的类同名但后缀为 _Impl 的类。
    1. 就你而言
      CarsDatabase_Impl
  4. 在类中会有一个名为createAllTables的方法(相当于java中的函数)。每个组件(表格、索引等)都会有一个
    _db.execSQL("....");
    1. 忽略room_master_table,Room将管理这张表
  5. 使用 SQL(由
    ....
    表示)作为迁移的基础。 Room 将使用 EXACT SQL,因此符合预期(实际需要)的架构。
    1. 即确切的数据类型以及重要的是确切的约束是由您决定的。
© www.soinside.com 2019 - 2024. All rights reserved.