پیش‌تکمیل کردن پایگاه داده Room

اگر می‌خواهید برنامه‌تان با پایگاه داده‌ای شروع شود که ازقبل با مجموعه خاصی از داده‌ها بار شده است، می‌توانید پایگاه داده را ازپیش تکمیل کنید. در Room، می‌توانید از واسط‌های برنامه‌سازی کاربردی برای پیش‌پر کردن پایگاه داده در زمان مقداردهی اولیه با محتوای فایل پایگاه داده ازپیش بسته‌بندی‌شده در سیستم فایل دستگاه استفاده کنید.

ازپیش پر کردن از دارایی برنامه

برای پیش‌پر کردن پایگاه داده Room از فایل پایگاه داده ازپیش بسته‌بندی‌شده‌ای که در هر جایی از دایرکتوری assets/ برنامه شما قرار دارد، تابع createFromAsset را از شیء RoomDatabase.Builder خود قبل‌از فراخوانی build فراخوانی کنید:

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

تابع createFromAsset آرگومان رشته‌ای را می‌پذیرد که حاوی مسیر نسبی از دایرکتوری assets/ به فایل پایگاه داده ازپیش بسته‌بندی‌شده است.

ازپیش پر کردن از سیستم فایل

برای پیش‌پر کردن پایگاه داده Room از فایل پایگاه داده ازپیش بسته‌بندی‌شده‌ای که در هر جایی از سیستم فایل دستگاه به‌جز دایرکتوری assets/ برنامه شما قرار دارد، پیش‌از فراخوانی build، تابع createFromFile را از شیء RoomDatabase.Builder فراخوانی کنید:

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

تابع createFromFile آرگومان File را برای فایل پایگاه داده ازپیش بسته‌بندی‌شده می‌پذیرد. ‫Room به‌جای باز کردن مستقیم فایل تعیین‌شده، نسخه‌ای از آن ایجاد می‌کند، بنابراین مطمئن شوید برنامه شما اجازه خواندن فایل را داشته باشد.

انتقال‌هایی را که شامل پایگاه‌های داده ازپیش بسته‌بندی‌شده است مدیریت کنید

فایل‌های پایگاه داده ازپیش بسته‌بندی‌شده همچنین می‌توانند نحوه مدیریت انتقال‌های بازگشتی توسط پایگاه داده Room را تغییر دهند. معمولاً وقتی انتقال‌های مخرب فعال باشند و Room مجبور باشد انتقال را بدون مسیر انتقال انجام دهد، Room همه جدول‌های پایگاه داده را حذف می‌کند و پایگاه داده خالی با طرحواره مشخص‌شده برای نسخه مقصد ایجاد می‌کند. بااین‌حال، اگر فایل پایگاه داده پیش‌بسته‌بندی‌شده‌ای با همان شماره نسخه هدف اضافه کنید، Room پس‌از انجام انتقال مخرب، پایگاه داده‌ای را که به‌تازگی بازسازی شده است با محتوای فایل پایگاه داده پیش‌بسته‌بندی‌شده تکمیل می‌کند.

برای اطلاعات بیشتر درباره انتقال‌های پایگاه داده Room، به انتقال پایگاه داده Room مراجعه کنید.

بخش‌های زیر چند نمونه از نحوه عملکرد این موضوع در عمل را ارائه می‌دهند.

مثال: انتقال به پایگاه داده ازپیش بسته‌بندی‌شده

فرض کنید موارد زیر را دارید:

  • برنامه شما پایگاه داده Room را در نسخه ۳ تعریف می‌کند.
  • نسخه نمونه پایگاه داده که ازقبل در دستگاه نصب شده است نسخه ۲ است.
  • فایل پایگاه داده‌ای ازپیش بسته‌بندی‌شده‌ای وجود دارد که در نسخه ۳ است.
  • هیچ مسیر انتقال پیاده‌سازی‌شده‌ای از نسخه ۲ به نسخه ۳ وجود ندارد.
  • انتقال‌های مخرب فعال است.

// 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. چون پایگاه داده تعریف‌شده در برنامه شما نسخه ۳ است و نمونه پایگاه داده ازقبل نصب‌شده در دستگاه نسخه ۲ است، انتقال لازم است.
  2. چون طرح انتقال پیاده‌سازی‌شده‌ای از نسخه ۲ به نسخه ۳ وجود ندارد، انتقال یک انتقال برگشتی است.
  3. چون تابع سازنده fallbackToDestructiveMigration را فراخوانی می‌کنید، انتقال به حالت برگشتی مخرب است. ‫Room نمونه پایگاه داده‌ای را که در دستگاه نصب شده است حذف می‌کند.
  4. چون فایل پایگاه داده ازپیش بسته‌بندی‌شده‌ای وجود دارد که در نسخه ۳ است، Room پایگاه داده را بازسازی می‌کند و آن را بااستفاده از محتوای فایل پایگاه داده ازپیش بسته‌بندی‌شده تکمیل می‌کند. اگر فایل پایگاه داده پیش‌بسته‌بندی‌شده شما در نسخه ۲ باشد، Room تشخیص می‌دهد که با نسخه هدف مطابقت ندارد و از آن برای انتقال داده بازگشتی استفاده نمی‌کند.

مثال: انتقال با پایگاه داده ازپیش بسته‌بندی‌شده اجرا شد

فرض کنید برنامه شما به‌جای آن مسیر انتقالی از نسخه ۲ به نسخه ۳ را پیاده‌سازی می‌کند:

// 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. چون پایگاه داده تعریف‌شده در برنامه شما در نسخه ۳ است و پایگاه داده ازقبل نصب‌شده در دستگاه در نسخه ۲ است، انتقال لازم است.
  2. چون مسیر انتقال پیاده‌سازی‌شده‌ای از نسخه ۲ به نسخه ۳ وجود دارد، ‫Room تابع migrate تعریف‌شده را اجرا می‌کند تا نمونه پایگاه داده در دستگاه را به نسخه ۳ به‌روز کند و داده‌هایی را که ازقبل در پایگاه داده وجود دارد حفظ کند. ‫Room از فایل پایگاه داده ازپیش بسته‌بندی‌شده استفاده نمی‌کند، زیرا Room فقط درصورت مهاجرت عقب‌گرد از فایل‌های پایگاه داده ازپیش بسته‌بندی‌شده استفاده می‌کند.

مثال: انتقال چندمرحله‌ای با پایگاه داده ازپیش بسته‌بندی‌شده

فایل‌های پایگاه داده ازپیش بسته‌بندی‌شده نیز می‌توانند بر انتقال‌هایی که از چندین مرحله تشکیل شده‌اند تأثیر بگذارند. مورد زیر را درنظر بگیرید:

  • برنامه شما پایگاه داده Room را در نسخه ۴ تعریف می‌کند.
  • نسخه نمونه پایگاه داده که ازقبل در دستگاه نصب شده است نسخه ۲ است.
  • فایل پایگاه داده‌ای ازپیش بسته‌بندی‌شده‌ای وجود دارد که نسخه ۳ است.
  • مسیر انتقال پیاده‌سازی‌شده‌ای از نسخه ۳ به نسخه ۴ وجود دارد، اما از نسخه ۲ به نسخه ۳ وجود ندارد.
  • انتقال‌های مخرب فعال است.

// 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. چون پایگاه داده تعریف‌شده در برنامه شما در نسخه ۴ است و نمونه پایگاه داده‌ای که ازقبل در دستگاه نصب شده است در نسخه ۲ است، انتقال لازم است.
  2. چون مسیر انتقال پیاده‌سازی‌شده‌ای از نسخه ۲ به نسخه ۳ وجود ندارد، انتقال یک انتقال برگشتی است.
  3. چون تابع سازنده fallbackToDestructiveMigration را فراخوانی می‌کنید، انتقال به حالت برگشتی مخرب است. ‫Room نمونه پایگاه داده را در دستگاه حذف می‌کند.
  4. چون فایل پایگاه داده ازپیش بسته‌بندی‌شده‌ای وجود دارد که در نسخه ۳ است، Room پایگاه داده را بازسازی می‌کند و آن را بااستفاده از محتوای فایل پایگاه داده ازپیش بسته‌بندی‌شده تکمیل می‌کند.
  5. پایگاه داده نصب‌شده در دستگاه اکنون در نسخه ۳ است. چون هنوز از نسخه تعریف‌شده در برنامه شما پایین‌تر است، مهاجرت دیگری لازم است.
  6. چون مسیر انتقال پیاده‌سازی‌شده‌ای از نسخه ۳ به نسخه ۴ وجود دارد، ‫Room تابع migrate تعریف‌شده را برای به‌روزرسانی نمونه پایگاه داده در دستگاه به نسخه ۴ اجرا می‌کند و داده‌هایی را که از فایل پایگاه داده پیش‌بسته‌بندی‌شده نسخه ۳ کپی شده است حفظ می‌کند.