Room veritabanınızı önceden doldurma

Uygulamanızın belirli bir veri grubuyla önceden yüklenmiş bir veritabanıyla başlamasını istiyorsanız veritabanını önceden doldurabilirsiniz. Room'da, başlatma sırasında cihazın dosya sistemindeki önceden paketlenmiş bir veritabanı dosyasının içeriğiyle bir veritabanını önceden doldurmak için API'leri kullanabilirsiniz.

Uygulama öğesinden önceden doldurma

Uygulamanızın assets/ dizininde herhangi bir yerde bulunan önceden paketlenmiş bir veritabanı dosyasından Room veritabanını önceden doldurmak için build işlevini çağırmadan önce RoomDatabase.Builder nesnenizden createFromAsset işlevini çağırın:

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

createFromAsset işlevi, assets/ dizininden önceden paketlenmiş veritabanı dosyasına giden göreli yolu içeren bir dize bağımsız değişkenini kabul eder.

Dosya sisteminden önceden doldurma

Cihazın dosya sisteminde ancak uygulamanızın assets/ dizininde bulunmayan önceden paketlenmiş bir veritabanı dosyasından Room veritabanını önceden doldurmak için build işlevini çağırmadan önce RoomDatabase.Builder nesnenizden createFromFile işlevini çağırın:

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

createFromFile işlevi, önceden paketlenmiş veritabanı dosyası için File bağımsız değişkenini kabul eder. Room, belirlenen dosyayı doğrudan açmak yerine kopyasını oluşturur. Bu nedenle, uygulamanızın dosya üzerinde okuma izni olduğundan emin olun.

Önceden paketlenmiş veritabanlarını içeren taşıma işlemlerini yönetme

Önceden paketlenmiş veritabanı dosyaları, Room veritabanınızın yedek geçişleri işleme şeklini de değiştirebilir. Normalde, yıkıcı taşıma işlemleri etkinleştirildiğinde ve Room'un taşıma yolu olmadan taşıma işlemi gerçekleştirmesi gerektiğinde Room, veritabanındaki tüm tabloları bırakır ve hedef sürüm için belirtilen şemaya sahip boş bir veritabanı oluşturur. Ancak, hedef sürümle aynı numaraya sahip önceden paketlenmiş bir veritabanı dosyası eklerseniz Room, yıkıcı taşıma işlemini gerçekleştirdikten sonra yeni oluşturulan veritabanını önceden paketlenmiş veritabanı dosyasının içeriğiyle doldurur.

Room veritabanı taşıma işlemleri hakkında daha fazla bilgi için Room veritabanınızı taşıma başlıklı makaleyi inceleyin.

Aşağıdaki bölümlerde, bu özelliğin uygulamada nasıl çalıştığına dair birkaç örnek verilmiştir.

Örnek: Önceden paketlenmiş bir veritabanıyla yedek taşıma

Aşağıdaki bilgileri dikkate alın:

  • Uygulamanız, 3. sürümde bir Room veritabanı tanımlıyor.
  • Cihazda yüklü olan veritabanı örneği 2. sürümde.
  • 3. sürümde önceden paketlenmiş bir veritabanı dosyası vardır.
  • 2. sürümden 3. sürüme geçiş için uygulanmış bir taşıma yolu yoktur.
  • Veri kaybına neden olan taşıma işlemleri etkinleştirildi.

// 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()
}

Bu durumda şu işlemler gerçekleşir:

  1. Uygulamanızda tanımlanan veritabanı sürüm 3'te, cihazda yüklü olan veritabanı örneği ise sürüm 2'de olduğundan taşıma işlemi yapılması gerekir.
  2. Sürüm 2'den sürüm 3'e geçiş planı uygulanmadığından taşıma işlemi, yedek taşıma işlemidir.
  3. fallbackToDestructiveMigration oluşturucu işlevini çağırdığınız için yedek taşıma işlemi yıkıcıdır. Room, cihazda yüklü olan veritabanı örneğini bırakır.
  4. 3. sürümde önceden paketlenmiş bir veritabanı dosyası olduğundan Room, veritabanını yeniden oluşturur ve önceden paketlenmiş veritabanı dosyasının içeriğini kullanarak doldurur. Önceden paketlenmiş veritabanı dosyanız 2. sürümdeyse Room, dosyanın hedef sürümle eşleşmediğini belirler ve geri dönüş geçişi için kullanmaz.

Örnek: Önceden paketlenmiş bir veritabanıyla taşıma uygulandı

Bunun yerine, uygulamanızın sürüm 2'den sürüm 3'e taşıma yolu uyguladığını varsayalım:

// 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()
}

Bu durumda şu işlemler gerçekleşir:

  1. Uygulamanızda tanımlanan veritabanı 3. sürümde, cihazda yüklü olan veritabanı ise 2. sürümde olduğundan taşıma işlemi yapılması gerekir.
  2. 2. sürümden 3. sürüme uygulanan bir taşıma yolu olduğundan Room, cihazdaki veritabanı örneğini 3. sürüme güncellemek için tanımlanan migrate işlevini çalıştırır ve veritabanında bulunan verileri korur. Room, önceden paketlenmiş veritabanı dosyalarını yalnızca geri dönüş taşıma işleminde kullandığından önceden paketlenmiş veritabanı dosyasını kullanmaz.

Örnek: Önceden paketlenmiş bir veritabanıyla çok adımlı taşıma

Önceden paketlenmiş veritabanı dosyaları, birden fazla adımdan oluşan taşımaları da etkileyebilir. Aşağıdaki durumu ele alalım:

  • Uygulamanız, 4. sürümde bir Room veritabanı tanımlıyor.
  • Cihazda yüklü olan veritabanı örneği 2. sürümde.
  • 3. sürümde önceden paketlenmiş bir veritabanı dosyası vardır.
  • 3. sürümden 4. sürüme geçiş için bir taşıma yolu uygulanmıştır ancak 2. sürümden 3. sürüme geçiş için taşıma yolu uygulanmamıştır.
  • Veri kaybına neden olan taşıma işlemleri etkinleştirildi.

// 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()
}

Bu durumda şu işlemler gerçekleşir:

  1. Uygulamanızda tanımlanan veritabanı sürüm 4'te, cihazda yüklü olan veritabanı örneği ise sürüm 2'de olduğundan taşıma işlemi yapılması gerekir.
  2. Sürüm 2'den sürüm 3'e uygulanan bir taşıma yolu olmadığından taşıma işlemi, yedek taşıma işlemidir.
  3. fallbackToDestructiveMigration oluşturucu işlevini çağırdığınız için yedek taşıma işlemi yıkıcıdır. Room, cihazdaki veritabanı örneğini bırakır.
  4. 3. sürümde önceden paketlenmiş bir veritabanı dosyası olduğundan Room, veritabanını yeniden oluşturur ve önceden paketlenmiş veritabanı dosyasının içeriğini kullanarak doldurur.
  5. Cihazda yüklü olan veritabanı artık 3. sürümde. Uygulamanızda tanımlanan sürümden hâlâ düşük olduğundan başka bir taşıma işlemi yapılması gerekir.
  6. Sürüm 3'ten sürüm 4'e uygulanan bir taşıma yolu olduğundan Room, cihazdaki veritabanı örneğini sürüm 4'e güncellemek için tanımlanan migrate işlevini çalıştırır. Bu sırada, sürüm 3'ün önceden paketlenmiş veritabanı dosyasından kopyalanan veriler korunur.