Room Persistence Library: TypeConverters and Database Migration

Gonzalo Martin
AndroidPub
Published in
4 min readJul 22, 2017

--

After a light introduction of Room, I want to bring you a second review (and more specific) about some interesting features of Room.

If you haven’t seen the introduction of Room, you should read that before this article

Adding Type Converters

One of the useful feature of Room is Type Converters. When you have to store in database some custom types, you can use Type Converters. It converts from a unknown type into a known type in terms of database types.

Let’s create our first Converter class. Let’s name it DateTypeConverter

public class DateTypeConverter {

@TypeConverter
public static Date toDate(Long value) {
return value == null ? null : new Date(value);
}

@TypeConverter
public static Long toLong(Date value) {
return value == null ? null : value.getTime();
}
}

Some things to mention. Note we’ve added a new annotation TypeConverter, which allows you to persists a specific custom type into a database. In this case, the type Date is stored as a Long type into the database. Room knows primitive types to store, for that reason we can use TypeConverter to convert an unknown type into a known database type.

You can see we’ve defined 2 functions:

  • toDate: converts a Long value into a Date type
  • toLong: converts a Date value into a Long type

Room uses those functions to store and load that value from database.

Once you’ve defined the converter class, we have to reference it in our database definition class (already created):

@Database(entities = {Product.class}, version = 1)
@TypeConverters({DateTypeConverter.class})
public abstract class MyDatabase extends RoomDatabase {
public abstract ProductDao productDao();
}

Note we’ve added a new annotation named TypeConverters in our database definition in order to reference the different converters that we can have (you can separate it by commas and add others).

Nothing more to do for now. You can check those changes in the following commit:

Migrating your Database

Well, in every system with database we should execute migrations at least one time if we want to update some column of our database.

Room is not the exception. It implements an abstract layer to upgrade our database in an understandable way.

As we know, if you change the database schema but you don’t update the version number, the app will crash at first time. This isn’t new. We have to update our database version number when we change our database schema.

Well, to do that in Room, we have to add our new change in our entity class first. Let’s add price attribute to our Product entity:

@Entity
public class Product {

...
@ColumnInfo(name = "price")
private int price;

public int getPrice() {
return price;
}

public void setPrice(Long price) {
this.price = price;
}
...

Up to now, everything is equal than before. Let’s move to our database definition class and let’s update the version number to 2:

@Database(entities = {Product.class}, version = 2)
@TypeConverters({DateTypeConverter.class})
public abstract class MyDatabase extends RoomDatabase {
public abstract ProductDao productDao();
}

Perfect! We have to do two steps more to finalize our database migration.

We have to implement the migration from version 1 to 2. To do that, we have to define migration as a static variable (named it as you whatever you want):

public static final Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE product "
+ " ADD COLUMN price INTEGER");
}
};

The above sentence would be translated as:

“when the database version number is changed to 2, executes this migration: add a column named price with INTEGER type in table product

Nice! We have to do the last step. We need to tell to our database instantiation that executes this migration when it is called. Let’s move to our database instantiation place. We had defined it in our Application class:

database = Room.databaseBuilder(getApplicationContext(), MyDatabase.class, DATABASE_NAME)
.addMigrations(MyDatabase.MIGRATION_1_2)
.build();

We’ve indicated to Room to execute the created migration before.

If you have multiple migrations, you can call them from here separated by commas.

Well that’s all! You can execute your application now and cross fingers :)

To review those changes, you can see the following commit:

I hope you could get more knowledge about this library now. I will post more articles in the future. Keep watch! :)

Check the following post about pre-population of Room database:

--

--