Android Room Upgrade Database Add New Table (Migration) - Kotlin

October 22, 2018

Configure Module build.gradle to export schema and allow testing. Observe // NEW comments.

Based on Android Room Database Migration Instrumented Unit Test.

android {
    ...

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

        // NEW
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
            }
        }
    }

    // NEW
    sourceSets {
        androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
    }
}

dependencies {
    def android_room_version = '1.1.1'
    implementation "android.arch.persistence.room:runtime:$android_room_version"
    kapt "android.arch.persistence.room:compiler:$android_room_version"
    // NEW
    androidTestImplementation "android.arch.persistence.room:testing:$android_room_version"
}

Make sure exportSchema = true for @Database, else schema json won’t be generated and later you might bump into FileNotFoundException: Cannot find the schema file in the assets folder.

@Database(entities = [(Pin::class)], version = 1, exportSchema = true)
@TypeConverters(RoomConverters::class)
abstract class AppDatabase : RoomDatabase() {
    abstract fun pinDao(): PinDao
}

Make/Compile/Build project (don’t Run/Deploy) and it shall generate 1.json at assets/[DatabaseClassPath] (Android view) or /app/schemas/[DatabaseClassPath] (Project view).

Change Database Version to 2.

NOTE: Important to change Database Version before applying changes to table and column. This is to ensure the database schema generated is accurate based on the database version.

@Database(entities = [...], version = 2, exportSchema = true)

Create the new Entity/Table.

@Entity(tableName = "album")
data class Album (
        @PrimaryKey(autoGenerate = true)
        @ColumnInfo(name = "id") var id: Long = 0,
        @ColumnInfo(name = "created") var created: LocalDateTime = LocalDateTime.now(ZoneOffset.UTC),
        @ColumnInfo(name = "modified") var modified: LocalDateTime = created,
        @ColumnInfo(name = "name") var name: String = ""
        )

Add to @Database annotation.

@Database(entities = [(Pin::class), (Album::class)], version = 2, exportSchema = true)

Make/Compile/Build project (don’t Run/Deploy) and it shall generate 2.json at assets/[DatabaseClassPath] (Android view) or /app/schemas/[DatabaseClassPath] (Project view).

Look inside 2.json and you shall find the createSql for new album table.

{
  "tableName": "album",
  "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `created` INTEGER NOT NULL, `modified` INTEGER NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`id`))",
        
}

Based on Android Room Database Migration (Upgrade Version), create the Migration class.

Create file DatabaseMigration.kt to handle database migration from Version 1 -> 2.

Copy the createSql from 2.json. Replace ${TABLE_NAME}.

val MIGRATION_1_2: Migration = object : Migration(1, 2) {
    override fun migrate(database: SupportSQLiteDatabase) {
        // https://developer.android.com/reference/android/arch/persistence/room/ColumnInfo
        /*
        database.execSQL("ALTER TABLE pin "
                + " ADD COLUMN is_location_accurate INTEGER NOT NULL DEFAULT 0")
        database.execSQL("UPDATE pin "
                + " SET is_location_accurate = 0 WHERE lat IS NULL")
        database.execSQL("UPDATE pin "
                + " SET is_location_accurate = 1 WHERE lat IS NOT NULL")
                */
        database.execSQL("CREATE TABLE IF NOT EXISTS `album` (`id` INTEGER NOT NULL, `created` INTEGER NOT NULL, `modified` INTEGER NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`id`))")"
    }
}

Add addMigrations to Room.databaseBuilder.

val database = Room.databaseBuilder(app, AppDatabase::class.java, "PixPin.db")
        // addMigrations(MIGRATION_1_2, MIGRATION_2_3)
        .addMigrations(MIGRATION_1_2)
        .build()

If you want to test it before deploying the migration to your device, refer to Android Room Database Migration Instrumented Unit Test.

Else, Run the project.

References:

This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.