添加表格时房间迁移失败

Posted

技术标签:

【中文标题】添加表格时房间迁移失败【英文标题】:Room Migration Failed When Adding Table 【发布时间】:2022-01-22 12:56:24 【问题描述】:

我正在尝试对我的数据库执行迁移。

我要添加的表如下:

@Entity(tableName = "Recipe_Of_Day_Entity")
data class RecipeOfDayDTO(
    @PrimaryKey
    @ColumnInfo(name = "id")
    val id : String = UUID.randomUUID().toString(),
    @ColumnInfo(name = "vegetarian")
    val vegetarian: Boolean,
    @ColumnInfo(name = "vegan")
    val vegan: Boolean,
    @ColumnInfo(name = "glutenFree")
    val glutenFree: Boolean,
    @ColumnInfo(name = "dairyFree")
    val dairyFree: Boolean,
    @ColumnInfo(name = "veryHealthy")
    val veryHealthy: Boolean,
    @ColumnInfo(name = "image")
    val image: String?,
    @ColumnInfo(name = "imageType")
    val imageType: String?,
    @ColumnInfo(name = "instructions")
    val instructions: String?) 

迁移对象定义如下:

val MIGRATION_4_5: Migration = object : Migration(4, 5) 
    override fun migrate(database: SupportSQLiteDatabase) 
        // https://developer.android.com/reference/android/arch/persistence/room/ColumnInfo
        database.execSQL("CREATE TABLE IF NOT EXISTS `RecipeOfDayDTO` (`id` TEXT NOT NULL, `vegetarian` " +
                "INTEGER NOT NULL, `vegan` INTEGER NOT NULL, `glutenFree` INTEGER NOT NULL, `dairyFree` INTEGER NOT NULL," +
                "`veryHealthy` INTEGER NOT NULL, `image` TEXT NOT NULL, `imageType` TEXT NOT NULL, `instructions` TEXT NOT NULL)")
    

我正在构建数据库如下:

@Database(entities = [IngredientDataClassDTO::class, RecipeNotificationClassDTO::class, RecipeOfDayDTO::class], version = 5, exportSchema = true)
abstract class IngredientDatabase : RoomDatabase() 
.
.
.
Room.databaseBuilder(
                        context.applicationContext,
                        IngredientDatabase::class.java,
                        "saved_ingredient_database"
                    )
           
                        // https://medium.com/androiddevelopers/understanding-migrations-with-room-f01e04b07929
                        .addMigrations(MIGRATION_4_5)
                        .build()

我已确保Room Database Migration doesnt properly handle ALTER TABLE migration 中建议的预期和找到的表之间没有区别。事实上,我使用了文本检查器,唯一的区别是“PrimaryKeyPosition”,这在我刚才提到的链接中不是问题。

我不想破坏我以前的数据库,所以我避免使用 fallbackToDestructiveMigration()。无效和重新启动并没有消除错误。有没有其他人遇到过这个问题?

【问题讨论】:

我认为这个解决方案会帮助你github.com/orbitalsonic/… 【参考方案1】:

RecipeOfDayDTO.image,RecipeOfDayDTO.imageType,RecipeOfDayDTO.instructions是可以为空的String,所以你的迁移SQL一定是这样的;

database.execSQL("CREATE TABLE IF NOT EXISTS `RecipeOfDayDTO` (`id` TEXT NOT NULL, `vegetarian` " +
                "INTEGER NOT NULL, `vegan` INTEGER NOT NULL, `glutenFree` INTEGER NOT NULL, `dairyFree` INTEGER NOT NULL," +
                "`veryHealthy` INTEGER NOT NULL, `image` TEXT NULL, `imageType` TEXT NULL, `instructions` TEXT NULL, PRIMARY KEY(`id`))")```

【讨论】:

感谢您的回复!我更改了它,但仍然缺少“PRIMARY KEY(id)”,现在一切正常!【参考方案2】:

匹配期望和找到的方法是对带有@Entity注释的类进行更改,确保该类被定义为@Database类的实体列表中的实体,然后编译(CTRL + F9) 然后检查生成的 java (通过 Android View)。

您查看同名但后缀为 _Impl 的类,该类使用 @Database 注释,并查看名为 createAllTables 的方法,该方法具有 Room 为每个表所期望的 SQL。然后,为新表复制相应的 SQL 就很简单了。对于其他更改,例如更改表,您可以根据生成的 java 中的 SQL 生成结果表/列。

例如将 RecipeOfDayDTO 添加到现有项目,然后将其添加到 @Database 类

导致在生成的 java 中找到以下方法:-

  @Override
  public void createAllTables(SupportSQLiteDatabase _db) 
    _db.execSQL("CREATE TABLE IF NOT EXISTS `NoteEntity` (`id` INTEGER, `startRef` INTEGER NOT NULL, `endRef` INTEGER NOT NULL, `content` TEXT NOT NULL, PRIMARY KEY(`id`))");
    _db.execSQL("CREATE TABLE IF NOT EXISTS `Recipe_Of_Day_Entity` (`id` TEXT NOT NULL, `vegetarian` INTEGER NOT NULL, `vegan` INTEGER NOT NULL, `glutenFree` INTEGER NOT NULL, `dairyFree` INTEGER NOT NULL, `veryHealthy` INTEGER NOT NULL, `image` TEXT, `imageType` TEXT, `instructions` TEXT, PRIMARY KEY(`id`))");
    _db.execSQL("CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)");
    _db.execSQL("INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'c8707866be882430083eee62243a71ed')");
  

所以这只是复制 SQL 的问题:-

"CREATE TABLE IF NOT EXISTS `Recipe_Of_Day_Entity` (`id` TEXT NOT NULL, `vegetarian` INTEGER NOT NULL, `vegan` INTEGER NOT NULL, `glutenFree` INTEGER NOT NULL, `dairyFree` INTEGER NOT NULL, `veryHealthy` INTEGER NOT NULL, `image` TEXT, `imageType` TEXT, `instructions` TEXT, PRIMARY KEY(`id`))"

进入迁移,无需花时间试图确定什么匹配和不匹配。

对于 2.4.0-aplh01 和更高版本,Room 还支持自动迁移(可以处理添加表格而没有复杂性)。但是,它们依赖于 exportSchema 选项是否为真,并且之前和之后的版本都存在这样的模式。

见https://developer.android.com/training/data-storage/room/migrating-db-versions

【讨论】:

谢谢!对于未来的读者,要获取生成的 Java 文件,请单击您的数据库标题并按 CTRL + B 以查看该数据库的用法。正如@MikeT 提到的,它将以_Impl 为后缀,单击该Java 文件并将SQL 文本复制到您的迁移对象。

以上是关于添加表格时房间迁移失败的主要内容,如果未能解决你的问题,请参考以下文章

Android 房间迁移测试失败,但没有任何改变

生成 Android 房间迁移的最佳方法是啥?

Android房间迁移添加枚举列表

在房间中创建表格的方法[重复]

仅向多个表的主键添加 @NonNull 注释的房间迁移

在 Android 中使用房间数据库写入迁移的查询错误