如果您希望應用程式首先處理已載入特定資料集的資料庫,可以預先填入資料庫。在 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() }
在這種情況下會發生下列情況:
- 由於應用程式中定義了第 3 版資料庫,而裝置上已經安裝的資料庫執行個體為第 2 版,因此必須遷移。
- 由於沒有實作從第 2 版到第 3 版的遷移計畫,因此這項遷移作業屬於備援遷移作業。
- 由於您呼叫
fallbackToDestructiveMigration建構工具函式,因此備用遷移作業具有破壞性。Room 會捨棄裝置上已經安裝的資料庫執行個體。 - 由於存在第 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() }
在這種情況下會發生下列情況:
- 由於應用程式中定義了第 3 版資料庫,而裝置上已經安裝的資料庫為第 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() }
在這種情況下會發生下列情況:
- 由於應用程式中定義了第 4 版資料庫,而裝置上已經安裝的資料庫執行個體為第 2 版,因此必須遷移。
- 由於沒有實作從第 2 版到第 3 版的遷移路徑,因此這項遷移作業屬於備援遷移作業。
- 由於您呼叫
fallbackToDestructiveMigration建構工具函式,因此備用遷移作業具有破壞性。Room 會捨棄裝置上的資料庫執行個體。 - 由於存在第 3 版預先封裝的資料庫檔案,因此 Room 會重新建立該資料庫,並填入預先封裝的資料庫檔案內容。
- 裝置上安裝的資料庫版本現在為第 3 版。但仍然低於應用程式中定義的版本,因此必須再次進行遷移。
- 由於已經實作從第 3 版到第 4 版的遷移路徑,因此 Room 會執行定義的
migrate函式,將裝置上的資料庫執行個體更新為第 4 版,並保留從第 3 版預先封裝的資料庫檔案中複製的資料。