Room的迁移系统不太好,至少直到2.1.0-alpha03
版本。
因此,在我们有更好的迁移系统之前,有一些解决方法可以让Room的迁移更容易。
由于没有@Database(createNewTables = true)
或MigrationSystem.createTable(User::class)
这样的方法,而应该有其中一个或另一个,唯一可能的方法是运行
CREATE TABLE IF NOT EXISTS `User` (`id` INTEGER, PRIMARY KEY(`id`))
在你的migrate
方法内部。
val MIGRATION_1_2 = object : Migration(1, 2){
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE TABLE IF NOT EXISTS `User` (`id` INTEGER, PRIMARY KEY(`id`))")
}
}
为了获得上述SQL脚本,您有4种方法。
1. 自己编写
基本上,您必须编写与Room生成的脚本匹配的上述脚本。这种方式是可行的,但不切实际。(考虑您有50个字段)
2.导出模式
如果在您的@Database
注释中包含exportSchema = true
,Room将在项目文件夹的/schemas中生成数据库模式。用法如下:
@Database(entities = [User::class], version = 2, exportSchema = true)
abstract class AppDatabase : RoomDatabase {
//...
}
请确保在您的应用程序模块的build.grade
中包含以下行:
Make sure that you have included below lines in build.grade
of your app module
kapt {
arguments {
arg("room.schemaLocation", "$projectDir/schemas".toString())
}
}
当您运行或构建项目时,会得到一个名为
2.json
的JSON文件,其中包含您的Room数据库中的所有查询。
"formatVersion": 1,
"database": {
"version": 2,
"identityHash": "325bd539353db508c5248423a1c88c03",
"entities": [
{
"tableName": "User",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
因此,您可以在migrate
方法中包含上述createSql
。
3. 从AppDatabase_Impl获取查询
如果您不想导出模式,仍然可以通过运行或构建项目来获取查询,这将生成AppDatabase_Impl.java
文件。在指定的文件中,您可以拥有。
@Override
public void createAllTables(SupportSQLiteDatabase _db) {
_db.execSQL("CREATE TABLE IF NOT EXISTS `User` (`id` INTEGER, PRIMARY KEY(`id`))");
在createAllTables
方法中,将包含所有实体的创建脚本。您可以获取它并在migrate
方法中包含。
4. 注解处理。
正如您所猜测的那样,Room在编译时使用注解处理生成上述所有schema
和AppDatabase_Impl
文件,您可以添加注解处理。
kapt "androidx.room:room-compiler:$room_version"
这意味着你也可以做同样的事情,创建你自己的注解处理库来为 Room 注解的 @Entity 和 @Database 生成所有必要的 create 查询语句。
这个想法是为 Room 注解的 @Entity 和 @Database 创建一个注解处理库。以被 @Entity 注解的类为例,以下是需要遵循的步骤:
1. 创建一个新的 StringBuilder 并添加 "CREATE TABLE IF NOT EXISTS "
2. 从 class.simplename 或者 @Entity 的 tableName 字段获取表名,并将它添加到你的 StringBuilder 中
3. 对于类的每个字段,根据字段本身或 @ColumnInfo 注解获取字段的名称、类型和可空性,为每个字段创建 SQL 列。对于每个字段,你需要将
id INTEGER NOT NULL
类型的列添加到你的 StringBuilder 中。
4. 通过 @PrimaryKey 添加主键。
5. 如果存在,则添加 ForeignKey 和 Indices。
6. 完成后将其转换为字符串并保存在你想使用的某个新类中。例如,像下面这样保存它。
public final class UserSqlUtils {
public String createTable = "CREATE TABLE IF NOT EXISTS User (id INTEGER, PRIMARY KEY(id))";
}
然后,您可以将其用作
val MIGRATION_1_2 = object : Migration(1, 2){
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(UserSqlUtils().createTable)
}
}
我为自己制作了一个库,你可以查看并在你的项目中使用。请注意,我制作的库并不完整,仅满足我创建表格的要求。
RoomExtension提供更好的迁移功能
使用RoomExtension的应用程序
希望这有用。
更新
在撰写本答案时,room版本为2.1.0-alpha03
,当我给开发人员发送电子邮件时,我得到了以下回复:
预计在2.2.0
中有更好的迁移系统
不幸的是,我们仍然缺乏更好的迁移系统。