Android Architecture Components: Room — Migration
This post was published in Android Weekly #285 issue
Hi! This is the last post in the series of Architecture Components articles. This time I’d like to present you migration of a Room database.
If you haven’t read previous articles, you can do it here:
Android Architecture Components: Room — Introduction
Android Architecture Components: Room — Relationships
Android Architecture Components: Room — Custom Types
Either way, I encourage you to read todays post. Let’s start!
Migration
Sometimes there’a s need to change our existing database schema. If we’ll add, update or delete some fields in the database and then run our application, we’ll see exception from Room:
java.lang.IllegalStateException: Room cannot verify the data integrity. Looks like you’ve changed schema but forgot to update the version number. You can simply fix this by increasing the version number.
Room will discover that it’s schema has changed and it‘s no more consistent with database version. Now if we’ll increment version number and run application once again, we’ll see another exception:
java.lang.IllegalStateException: A migration from 1 to 2 is necessary. Please provide a Migration in the builder or call fallbackToDestructiveMigration in the builder in which case Room will re-create all of the tables.
Now Room doesn’t know how to migrate database from version 1 to version 2. In this error Room suggest us two solutions:
- drop and recreate the whole database
- upgrade existing database schema to the newer version
First option is the easiest one, but it’s not the best for the users, as we’ll clear the whole database…
Despite I don’t recommend this solution, it’s possible with Room. To do it we need to add one line to the database builder:
Room.databaseBuilder(context, RepoDatabase.class, DB_NAME)
.fallbackToDestructiveMigration()
.build();
But, If we’d like to have our application more user-friendly, we can provide migration of our database. With Room it’s also quite easy. To do it we need to declare migration in database builder:
Room.databaseBuilder(context, RepoDatabase.class, DB_NAME)
.addMigrations(FROM_1_TO_2)
.build();static final Migration FROM_1_TO_2 = new Migration(1, 2) {
@Override
public void migrate(final SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE Repo
ADD COLUMN createdAt TEXT");
}
};
To the Migration object we simply pass version numbers and SQL statement to make a migration.
Now, something what’s the biggest advantage of Room, auto-generation of SQL statements, is unfortunately something what may bother us upon database migration as we don’t have proper statements. Luckily, there’s a solution for that:
android {
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation":
"$projectDir/schemas".toString()]
}
}
}
}
Thanks to this code fragment added to build.gradle
file we’ll be able to get those auto-generated by Room SQL statements and use them to make a migration:
"tableName": "Repo",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT, `url` TEXT, PRIMARY KEY(`id`))"
Files are located accordingly in app/schemas/your.package.name.RepoDatabase/
directory.
Conclusion
That’s all! I hope you liked that post. If you did — don’t forget to 👏 !
In this series there are also:
Android Architecture Components: Room — Introduction
Android Architecture Components: Room — Relationships
Android Architecture Components: Room — Custom Types
Android Architecture Components: ViewModel
Android Architecture Components: LiveData
Android Architecture Components: How to use LiveData with Data Binding?