iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 16
0
Software Development

Android Architecture系列 第 16

Room - Migration

  • 分享至 

  • xImage
  •  

一直覺得更新資料庫schema是很讓人緊張的事,如果出錯的話App的某些功能就會壞掉,甚至是App一打開就壞了。隨著更新次數增加,還要持續留意從某個舊版本升上來會不會出錯,真是越來越緊張。

慶幸的是,Room在這方面提供了很完善的實作和測試機制,我們今天先看實作的部分,測試就留到明天。

Migration

Room透過Migration來得知每次更新的具體內容,我們直接實作一個簡單的更新,例如要在Repo加上html_url欄位的話:

1.修改Entity
加上要新增的欄位html_url,其餘不變。

@Entity(...)
public class Repo {

    ...

    public String html_url;

    public Repo(...) {
        ...
    }
}

2.修改版本號
將version從1改成2。

@Database(entities = {RepoSearchResult.class, Repo.class}, version = 2)
public abstract class GithubDb extends RoomDatabase {
    abstract public RepoDao repoDao();
}

3.建立Migration
透過constructor Migration(int startVersion, int endVersion)建立版本1升級到2的內容。

@Database(entities = {RepoSearchResult.class, Repo.class}, version = 2)
public abstract class GithubDb extends RoomDatabase {
    ...

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

4.加至Builder
在databaseBuilder中加入這個Migration。

Room.databaseBuilder(app, GithubDb.class,"github.db")
                .addMigrations(MIGRATION_1_2)
                .build();

完成,以上四個就是簡單的更新步驟。

將來有其他更新時就重複1~3步驟,並在4加入新的Migration就可以了,例如:

Room.databaseBuilder(app, GithubDb.class,"github.db")
                .addMigrations(MIGRATION_1_2, MIGRATION_2_3)
                .build();

IllegalStateException

若有步驟漏掉時,Room會拋出IllegalStateException,並帶有蠻詳細的錯誤訊息,例如我們修改了Entity而沒實作其他步驟,會收到錯誤訊息:

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.

照著訊息的指引更新版本號,還是會錯,但收到不一樣的訊息:

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.

錯誤訊息給我們兩個選項,一是建立Migration,這樣就如同將上面的四個步驟做完了,所以其實不用怕漏掉步驟,Room都會提示;而第二個選項則是在builder加上fallbackToDestructiveMigration(),這樣的話Room會直接把table重建,原本的資料會全部清空,除非還在內部開發中,否則一般都不建議這樣做。

Migrate from SQLiteDatabase

如果原本是使用SQLiteDatabase,要轉移到Room的過程非常簡單,只要讓Room升級到版本2並提供一個空的Migration就可以了,節錄自Google sample

/**
 * Migrate from:
 * version 1 - using the SQLiteDatabase API
 * to
 * version 2 - using Room
 */
@VisibleForTesting
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        // Room uses an own database hash to uniquely identify the database
        // Since version 1 does not use Room, it doesn't have the database hash associated.
        // By implementing a Migration class, we're telling Room that it should use the data
        // from version 1 to version 2.
        // If no migration is provided, then the tables will be dropped and recreated.
        // Since we didn't alter the table, there's nothing else to do here.
    }
};

GitHub source code:
https://github.com/IvanBean/ITBon2018/tree/day16-room-migration

Reference:
Understanding migrations with Room
Android Architecture Components: Room — Migration


上一篇
Room - Relationships
下一篇
Test part 1:Room DAO and migration
系列文
Android Architecture30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言