Home > Net >  Room Migration Failed When Adding Table
Room Migration Failed When Adding Table

Time:12-21

I am trying to perform a migration on my database.

The table I am trying to add is as follows:

@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?) 

The migration object is defined below:

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)")
    }
}

I am building the database as below:

@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()

I have made sure that there are no difference between the expected and found tables as suggested in enter image description here

I don't want to destroy my previous database so I am avoiding using fallbackToDestructiveMigration(). Invalidating & Restarting did not remove the error. Has anyone else encountered this issue?

CodePudding user response:

RecipeOfDayDTO.image, RecipeOfDayDTO.imageType, RecipeOfDayDTO.instructions is nullable String, so your migration SQL must be like that;

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)")```

CodePudding user response:

The way to match the expected and found is to make the changes to the class(es) annotated with @Entity, ensure that the class is defined as an entity in the list of entities of the @Database class and then compile (CTRL F9) and to then inspect the generated java (via Android View).

You look at the class that is he same name but suffixed with _Impl as the class annotated with @Database and at the method named createAllTables which has the SQL that Room expects for each table. It is then a simple matter of copying the respective SQL for the new table(s). For other changes such as altering a table you can base the resultant table(s)/columns on the SQL found in the generated java.

e.g. Adding RecipeOfDayDTO to an existing project and then adding the it to the @Database class

results in the following method being found in the generated 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')");
  }

So it's just a matter of copying the 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`))"

into the migration, no need to spend time trying to ascertain what does and doesn't match.

With version 2.4.0-aplh01 and greater Room also support Automated Migrations (which would handle adding a table without complexities). However, they rely upon the exportSchema option being true and such a schema existing for the before and after versions.

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

  • Related