Room Database Migrations

Room Database Migrations
Note: This article is part of the advanced Room series which covers all the details about the Room persistence library. You can read all the articles here:

So, let's get started.

Database migration is a very important concept in any application development. As we add and change features in your app, we have to update the schema of our database. Whenever there is a change in the schema of any of our tables, we need to write a migration for the existing application if we don’t want our users to lose all of their existing data.

For example, we can consider a table named users which contains information of users and it has 3 columns named uid, first_name and last_name. Now if we add a new column for age, we need to write a migration for altering the current table schema — i.e., adding a new column named age.

The Room persistence library allows us to write Migration classes to preserve user data in this manner. Each Migration class specifies a startVersion and endVersion. At runtime, Room runs each Migration class's migrate() method, using the correct order to migrate the database to a later version.

val MIGRATION_1_2 = object : Migration(1, 2) {
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL("ALTER TABLE users ADD COLUMN age INTEGER")
    }
}

Now we have created the migration object MIGRATION_1_2, we need to add it in the database configuration using database builder.

Room.databaseBuilder(
    applicationContext, 
    UserDatabase::class.java, 
    "users-db"
).addMigrations(MIGRATION_1_2)
.build()

Gracefully handle missing migration paths

After updating our database’s schemas, it’s possible that some on-device databases could still use an older schema version. If Room cannot find a migration rule for upgrading that device’s database from the older version to the current version, it throws an IllegalStateException which makes our app to crash.

To prevent the app from crashing when this situation occurs, call the fallbackToDestructiveMigration() builder method when creating the database.

Room.databaseBuilder(
    applicationContext, 
    UserDatabase::class.java, 
    "users-db"
).fallbackToDestructiveMigration()
.build()

The destructive recreation fallback logic includes several additional options:

  • If errors occur in specific versions of your schema history that you cannot solve with migration paths, use fallbackToDestructiveMigrationFrom(). This method indicates that you'd like Room to use the fallback logic only in cases where the database attempts to migrate from one of those problematic versions.
  • To perform a destructive recreation only when attempting a schema downgrade, use fallbackToDestructiveMigrationOnDowngrade() instead.

This is how migration is done using Room. Hope you enjoyed this blog. In the next blog, we are going to learn: Using Room with LiveData and other third-party libraries.

You can also connect with me on LinkedIn, Twitter, Facebook and Github.

Thank You!!!