如果仅添加新表,则会进行会议室数据库迁移

Pio*_*ski 73 java android database-migration android-room

不要假设,我有一个简单的房间数据库:

@Database(entities = {User.class}, version = 1)
abstract class AppDatabase extends RoomDatabase {
    public abstract Dao getDao();
}
Run Code Online (Sandbox Code Playgroud)

现在,我正在添加一个新实体:Pet并将版本提升为2:

@Database(entities = {User.class, Pet.class}, version = 2)
abstract class AppDatabase extends RoomDatabase {
    public abstract Dao getDao();
}
Run Code Online (Sandbox Code Playgroud)

当然,Room会抛出异常: java.lang.IllegalStateException: A migration from 1 to 2 is necessary.

假设,我没有更改User类(因此所有数据都是安全的),我必须提供只创建新表的迁移.所以,我正在调查Room生成的类,搜索生成的查询以创建我的新表,复制它并粘贴到迁移中:

final Migration MIGRATION_1_2 =
        new Migration(1, 2) {
            @Override
            public void migrate(@NonNull final SupportSQLiteDatabase database) {
                database.execSQL("CREATE TABLE IF NOT EXISTS `Pet` (`name` TEXT NOT NULL, PRIMARY KEY(`name`))");
            }
        };
Run Code Online (Sandbox Code Playgroud)

但是我觉得手动操作不方便.有没有办法告诉Room:我没有触及任何现有的表,所以数据是安全的.请为我创建迁移?

mus*_*off 40

确实具备良好的迁移系统,至少直到2.1.0-alpha03.

预计将有更好的移民系统 2.2.0

因此,在我们拥有更好的迁移系统之前,有一些解决方法可以在房间内轻松迁移.

由于没有这样的方法,@Database(createNewTables = true) 或者MigrationSystem.createTable(User::class)应该有一个或另一个方法,唯一可行的方法是运行

CREATE TABLE IF NOT EXISTS `User` (`id` INTEGER, PRIMARY KEY(`id`))
Run Code Online (Sandbox Code Playgroud)

在你的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`))")
    }
}
Run Code Online (Sandbox Code Playgroud)

为了获得上述SQL脚本,您有4种方法

1.自己写

基本上,您必须编写上述脚本,该脚本将与Room生成的脚本相匹配.这种方式是可行的,不可行.(考虑你有50个领域)

2.出口模式

如果exportSchema = true@Database注释中包含,则Room将在项目文件夹的/ schemas中生成数据库模式.用法是

@Database(entities = [User::class], version = 2, exportSchema = true)
abstract class AppDatabase : RoomDatabase {
   //...
}
Run Code Online (Sandbox Code Playgroud)

确保build.grade您的应用模块中包含以下行

kapt {
    arguments {
        arg("room.schemaLocation", "$projectDir/schemas".toString())
    }
} 
Run Code Online (Sandbox Code Playgroud)

当您运行或构建项目时,您将获得一个JSON文件2.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
          },
Run Code Online (Sandbox Code Playgroud)

因此,您可以createSql在您的migrate方法中包含上述内容.

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`))");
Run Code Online (Sandbox Code Playgroud)

createAllTables方法中,将存在所有实体的创建脚本.你可以得到它并包含在你的migrate方法中.

4.注释处理.

正如您可能猜到的那样,Room会生成上述所有内容schema,以及AppDatabase_Impl编译时的文件以及您添加的注释处理

kapt "androidx.room:room-compiler:$room_version"
Run Code Online (Sandbox Code Playgroud)

这意味着您也可以执行相同操作并创建自己的注释处理库,为您生成所有必需的创建查询.

我们的想法是为@Entity和的房间注释制作一个注释处理库@Database.拿一个用@Entity例如注释的类.这些是您必须遵循的步骤

  1. 制作一个新的StringBuilder并附加"CREATE TABLE IF NOT NOT EXISTS"
  2. class.simplename或从tableName字段获取表名@Entity.把它添加到你的StringBuilder
  3. 然后,为类的每个字段创建SQL列.通过字段本身或@ColumnInfo注释获取字段的名称,类型,可为空性.对于每个字段,您必须为您的字段添加id INTEGER NOT NULL列样式StringBuilder.
  4. 添加主键 @PrimaryKey
  5. 添加ForeignKey,Indices如果存在.
  6. 完成后将其转换为字符串并将其保存在您要使用的新类中.例如,保存如下

2.1.0-alpha03

public final class UserSqlUtils {
  public String createTable = "CREATE TABLE IF NOT EXISTS User (id INTEGER, PRIMARY KEY(id))";
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以将其用作

val MIGRATION_1_2 = object : Migration(1, 2){
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL(UserSqlUtils().createTable)
    }
}
Run Code Online (Sandbox Code Playgroud)

我为自己制作了这样一个图书馆,你可以查看,甚至在你的项目中使用它.请注意,我创建的库不完整,它只是满足我对表创建的要求.

RoomExtension可以更好地迁移

使用RoomExtension的应用程序

希望它有用.

  • 目前版本为 2.2.2,仍然没有更好的迁移:( 然而,这是一个很好的答案,为我节省了大量的工作,所以+1。 (6认同)
  • 您能指出您读到的2.2.x版会议室将具有更好的迁移能力吗?我找不到任何可以证明这一点的东西,并且由于我们当前正在开发2.1.0 Beta,因此目前尚不知道2.2.0中的内容。 (2认同)
  • @musooff 我实际上认为添加表创建是可以的。这是从“createAllTables”函数复制代码的最安全方法。 (2认同)

Vis*_*ndu 6

抱歉,Room 不支持自动创建表而不丢失数据。

必须编写迁移。否则,它将删除所有数据并创建新的表结构。