預先填入 Room 資料庫

如果您希望應用程式首先處理已載入特定資料集的資料庫,可以預先填入資料庫。在 Room 中,您可以使用 API 在初始化時,使用裝置檔案系統中預先封裝的資料庫檔案內容來預先填充資料庫。

從應用程式資產預先填入

如要從位於應用程式 assets/ 目錄任意位置的預先封裝資料庫檔案中預先填入 Room 資料庫,請先透過 RoomDatabase.Builder 物件呼叫 createFromAsset 函式,再呼叫 build

Room.databaseBuilder<AppDatabase>(appContext, "sample.db")
    .createFromAsset("database/myapp.db")
    .build()

createFromAsset 函式接受字串引數,其中包含從 assets/ 目錄到預先封裝資料庫檔案的相對路徑。

從檔案系統預先填入

如要從位於裝置檔案系統任意位置的預先封裝資料庫檔案中,預先填入 Room 資料庫,而非應用程式的 assets/ 目錄,請先透過 RoomDatabase.Builder 物件呼叫 createFromFile 函式,再呼叫 build

Room.databaseBuilder<AppDatabase>(appContext, "sample.db")
    .createFromFile(File("mypath"))
    .build()

createFromFile 函式接受預先封裝資料庫檔案的 File 引數。Room 會建立指定檔案的副本,而非直接開啟,因此請確認您的應用程式具備該檔案的讀取權限。

處理包含已預先封裝資料庫的遷移作業

預先封裝的資料庫檔案還可以變更 Room 資料庫處理備用遷移作業的方式。通常,如果啟用破壞性遷移作業,且 Room 必須在沒有遷移路徑的情況下執行遷移作業,則 Room 會捨棄資料庫中所有資料表,並建立具有目標版本指定結構定義的空白資料庫。不過,如果您納入的預先封裝資料庫檔案數量與目標版本相同,在執行破壞性遷移作業之後,Room 會將預先封裝的資料庫檔案內容,填入已經重新建立的資料庫。

如要進一步瞭解 Room 資料庫遷移作業,請參閱「遷移 Room 資料庫」。

以下各節舉例說明了 Room 的實際運作方式。

範例:使用預先封裝的資料庫進行備用遷移

假設下列事項:

  • 您的應用程式定義了第 3 版的 Room 資料庫。
  • 裝置上已經安裝第 2 版資料庫執行個體。
  • 存在第 3 版預先封裝的資料庫檔案。
  • 沒有實作從第 2 版到第 3 版的遷移路徑。
  • 已啟用破壞性遷移作業。

// Database class definition declaring version 3.
@Database(entities = [SampleEntity::class], version = 3)
abstract class FallbackAppDatabase : RoomDatabase() {
    // ...
}

fun createFallbackDb(appContext: Context) {
    Room.databaseBuilder<FallbackAppDatabase>(appContext, "sample.db")
        .createFromAsset("database/myapp.db")
        .fallbackToDestructiveMigration()
        .build()
}

在這種情況下會發生下列情況:

  1. 由於應用程式中定義了第 3 版資料庫,而裝置上已經安裝的資料庫執行個體為第 2 版,因此必須遷移。
  2. 由於沒有實作從第 2 版到第 3 版的遷移計畫,因此這項遷移作業屬於備援遷移作業。
  3. 由於您呼叫 fallbackToDestructiveMigration 建構工具函式,因此備用遷移作業具有破壞性。Room 會捨棄裝置上已經安裝的資料庫執行個體。
  4. 由於存在第 3 版預先封裝的資料庫檔案,因此 Room 會重新建立該資料庫,並填入預先封裝的資料庫檔案內容。如果預先封裝的資料庫檔案為第 2 版,Room 會判斷其與目標版本不符,且不會用於備份遷移作業。

範例:實作包含已預先封裝資料庫的遷移作業

假設應用程式實作了從第 2 版到第 3 版的遷移路徑:

// Database class definition declaring version 3.
@Database(entities = [SampleEntity::class], version = 3)
abstract class ImplementedAppDatabase : RoomDatabase() {
    // ...
}

// Migration path definition from version 2 to version 3.
val MIGRATION_2_3 = object : Migration(2, 3) {
    override suspend fun migrate(connection: SQLiteConnection) {
        // ...
    }
}

fun createImplementedDb(appContext: Context) {
    Room.databaseBuilder<ImplementedAppDatabase>(appContext, "sample.db")
        .createFromAsset("database/myapp.db")
        .addMigrations(MIGRATION_2_3)
        .build()
}

在這種情況下會發生下列情況:

  1. 由於應用程式中定義了第 3 版資料庫,而裝置上已經安裝的資料庫為第 2 版,因此必須遷移。
  2. 由於已實作從第 2 版到第 3 版的遷移路徑,因此 Room 會執行定義的 migrate 函式,將裝置上的資料庫執行個體更新為第 3 版,並保留資料庫中已有的資料。Room 不會使用預先封裝的資料庫檔案,因為 Room 只會在備用遷移作業時使用預先封裝的資料庫檔案。

範例:包含已預先封裝資料庫的多步驟遷移作業

預先封裝的資料庫檔案還會影響包含多個步驟的遷移作業。假設下列情況:

  • 應用程式定義了第 4 版的 Room 資料庫。
  • 裝置上已經安裝第 2 版資料庫執行個體。
  • 存在第 3 版預先封裝的資料庫檔案。
  • 已經實作從第 3 版到第 4 版遷移路徑,但沒有從第 2 版遷移至第 3 版。
  • 已啟用破壞性遷移作業。

// Database class definition declaring version 4.
@Database(entities = [SampleEntity::class], version = 4)
abstract class MultiStepAppDatabase : RoomDatabase() {
    // ...
}

val MIGRATION_3_4 = object : Migration(3, 4) {
    override suspend fun migrate(connection: SQLiteConnection) {
        // ...
    }
}

fun createMultiStepDb(appContext: Context) {
    Room.databaseBuilder<MultiStepAppDatabase>(appContext, "sample.db")
        .createFromAsset("database/myapp.db")
        .addMigrations(MIGRATION_3_4)
        .fallbackToDestructiveMigration()
        .build()
}

在這種情況下會發生下列情況:

  1. 由於應用程式中定義了第 4 版資料庫,而裝置上已經安裝的資料庫執行個體為第 2 版,因此必須遷移。
  2. 由於沒有實作從第 2 版到第 3 版的遷移路徑,因此這項遷移作業屬於備援遷移作業。
  3. 由於您呼叫 fallbackToDestructiveMigration 建構工具函式,因此備用遷移作業具有破壞性。Room 會捨棄裝置上的資料庫執行個體。
  4. 由於存在第 3 版預先封裝的資料庫檔案,因此 Room 會重新建立該資料庫,並填入預先封裝的資料庫檔案內容。
  5. 裝置上安裝的資料庫版本現在為第 3 版。但仍然低於應用程式中定義的版本,因此必須再次進行遷移。
  6. 由於已經實作從第 3 版到第 4 版的遷移路徑,因此 Room 會執行定義的 migrate 函式,將裝置上的資料庫執行個體更新為第 4 版,並保留從第 3 版預先封裝的資料庫檔案中複製的資料。