我在 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 数据库的路径?
假设您正在进行更改并需要保留数据(如果您不需要保留任何数据,则只需进行更改并卸载应用程序即可)。
无需锻炼/猜测 Room 期望什么的最简单方法是使用 Room 生成的 SQL。
@Entity
带注释的类。@Database
注解的类同名但后缀为 _Impl 的类。
CarsDatabase_Impl
_db.execSQL("....");
。
....
表示)作为迁移的基础。 Room 将使用 EXACT SQL,因此符合预期(实际需要)的架构。