আপনার রুম ডাটাবেস স্থানান্তর করুন

আপনি আপনার অ্যাপে বৈশিষ্ট্যগুলি যোগ এবং পরিবর্তন করার সাথে সাথে এই পরিবর্তনগুলি প্রতিফলিত করতে আপনাকে আপনার রুম সত্তা ক্লাস এবং অন্তর্নিহিত ডাটাবেস টেবিলগুলি সংশোধন করতে হবে। যখন কোনো অ্যাপ আপডেট ডাটাবেস স্কিমা পরিবর্তন করে তখন ডিভাইসের ডাটাবেসে থাকা ব্যবহারকারীর ডেটা সংরক্ষণ করা গুরুত্বপূর্ণ।

ক্রমবর্ধমান মাইগ্রেশনের জন্য রুম স্বয়ংক্রিয় এবং ম্যানুয়াল উভয় বিকল্পকে সমর্থন করে। স্বয়ংক্রিয় স্থানান্তরগুলি বেশিরভাগ প্রাথমিক স্কিমা পরিবর্তনের জন্য কাজ করে, তবে আরও জটিল পরিবর্তনের জন্য আপনাকে ম্যানুয়ালি মাইগ্রেশন পাথগুলি সংজ্ঞায়িত করতে হতে পারে।

স্বয়ংক্রিয় স্থানান্তর

দুটি ডাটাবেস সংস্করণের মধ্যে একটি স্বয়ংক্রিয় স্থানান্তর ঘোষণা করতে, @DatabaseautoMigrations সম্পত্তিতে একটি @AutoMigration টীকা যোগ করুন:

কোটলিন

// Database class before the version update.
@Database(
  version = 1,
  entities = [User::class]
)
abstract class AppDatabase : RoomDatabase() {
  ...
}

// Database class after the version update.
@Database(
  version = 2,
  entities = [User::class],
  autoMigrations = [
    AutoMigration (from = 1, to = 2)
  ]
)
abstract class AppDatabase : RoomDatabase() {
  ...
}

জাভা

// Database class before the version update.
@Database(
  version = 1,
  entities = {User.class}
)
public abstract class AppDatabase extends RoomDatabase {
  ...
}

// Database class after the version update.
@Database(
  version = 2,
  entities = {User.class},
  autoMigrations = {
    @AutoMigration (from = 1, to = 2)
  }
)
public abstract class AppDatabase extends RoomDatabase {
  ...
}

স্বয়ংক্রিয় মাইগ্রেশন স্পেসিফিকেশন

যদি রুম অস্পষ্ট স্কিমা পরিবর্তনগুলি সনাক্ত করে এবং এটি আরও ইনপুট ছাড়া একটি মাইগ্রেশন প্ল্যান তৈরি করতে না পারে, তবে এটি একটি কম্পাইল-টাইম ত্রুটি ছুড়ে দেয় এবং আপনাকে একটি AutoMigrationSpec বাস্তবায়ন করতে বলে। সাধারণত, এটি ঘটে যখন একটি মাইগ্রেশন নিম্নলিখিতগুলির মধ্যে একটিকে জড়িত করে:

  • একটি টেবিল মুছে ফেলা বা পুনঃনামকরণ।
  • একটি কলাম মুছে ফেলা বা পুনঃনামকরণ।

আপনি রুমকে অতিরিক্ত তথ্য দিতে AutoMigrationSpec ব্যবহার করতে পারেন যা সঠিকভাবে মাইগ্রেশন পাথ তৈরি করতে প্রয়োজন। একটি স্ট্যাটিক ক্লাস সংজ্ঞায়িত করুন যা আপনার RoomDatabase ক্লাসে AutoMigrationSpec প্রয়োগ করে এবং নিম্নলিখিতগুলির একটি বা একাধিক দিয়ে এটিকে টীকা দেয়:

একটি স্বয়ংক্রিয় মাইগ্রেশনের জন্য AutoMigrationSpec বাস্তবায়ন ব্যবহার করতে, সংশ্লিষ্ট @AutoMigration টীকাতে spec বৈশিষ্ট্য সেট করুন:

কোটলিন

@Database(
  version = 2,
  entities = [User::class],
  autoMigrations = [
    AutoMigration (
      from = 1,
      to = 2,
      spec = AppDatabase.MyAutoMigration::class
    )
  ]
)
abstract class AppDatabase : RoomDatabase() {
  @RenameTable(fromTableName = "User", toTableName = "AppUser")
  class MyAutoMigration : AutoMigrationSpec
  ...
}

জাভা

@Database(
  version = 2,
  entities = {AppUser.class},
  autoMigrations = {
    @AutoMigration (
      from = 1,
      to = 2,
      spec = AppDatabase.MyAutoMigration.class
    )
  }
)
public abstract class AppDatabase extends RoomDatabase {
  @RenameTable(fromTableName = "User", toTableName = "AppUser")
  static class MyAutoMigration implements AutoMigrationSpec { }
  ...
}

স্বয়ংক্রিয় স্থানান্তর সম্পূর্ণ হওয়ার পরে আপনার অ্যাপটিকে আরও কাজ করার প্রয়োজন হলে, আপনি onPostMigrate() প্রয়োগ করতে পারেন। আপনি যদি আপনার AutoMigrationSpec এ এই পদ্ধতিটি প্রয়োগ করেন, স্বয়ংক্রিয় স্থানান্তর সম্পূর্ণ হওয়ার পরে রুম এটিকে কল করে।

ম্যানুয়াল মাইগ্রেশন

যে ক্ষেত্রে একটি মাইগ্রেশন জটিল স্কিমা পরিবর্তন জড়িত, রুম স্বয়ংক্রিয়ভাবে একটি উপযুক্ত মাইগ্রেশন পথ তৈরি করতে সক্ষম নাও হতে পারে। উদাহরণস্বরূপ, যদি আপনি একটি টেবিলের ডেটা দুটি টেবিলে বিভক্ত করার সিদ্ধান্ত নেন, তাহলে রুমটি কীভাবে এই বিভাজনটি সম্পাদন করবে তা বলতে পারে না। এই ধরনের ক্ষেত্রে, আপনাকে অবশ্যই একটি Migration ক্লাস বাস্তবায়নের মাধ্যমে একটি মাইগ্রেশন পাথ ম্যানুয়ালি সংজ্ঞায়িত করতে হবে।

একটি Migration ক্লাস স্পষ্টভাবে Migration.migrate() পদ্ধতিকে ওভাররাইড করে একটি startVersion এবং একটি endVersion এর মধ্যে একটি মাইগ্রেশন পথকে সংজ্ঞায়িত করে। addMigrations() পদ্ধতি ব্যবহার করে আপনার ডাটাবেস বিল্ডারে আপনার Migration ক্লাস যোগ করুন:

কোটলিন

val MIGRATION_1_2 = object : Migration(1, 2) {
  override fun migrate(database: SupportSQLiteDatabase) {
    database.execSQL("CREATE TABLE `Fruit` (`id` INTEGER, `name` TEXT, " +
      "PRIMARY KEY(`id`))")
  }
}

val MIGRATION_2_3 = object : Migration(2, 3) {
  override fun migrate(database: SupportSQLiteDatabase) {
    database.execSQL("ALTER TABLE Book ADD COLUMN pub_year INTEGER")
  }
}

Room.databaseBuilder(applicationContext, MyDb::class.java, "database-name")
  .addMigrations(MIGRATION_1_2, MIGRATION_2_3).build()

জাভা

static final Migration MIGRATION_1_2 = new Migration(1, 2) {
  @Override
  public void migrate(SupportSQLiteDatabase database) {
    database.execSQL("CREATE TABLE `Fruit` (`id` INTEGER, "
      + "`name` TEXT, PRIMARY KEY(`id`))");
  }
};

static final Migration MIGRATION_2_3 = new Migration(2, 3) {
  @Override
  public void migrate(SupportSQLiteDatabase database) {
    database.execSQL("ALTER TABLE Book "
      + " ADD COLUMN pub_year INTEGER");
  }
};

Room.databaseBuilder(getApplicationContext(), MyDb.class, "database-name")
  .addMigrations(MIGRATION_1_2, MIGRATION_2_3).build();

যখন আপনি আপনার মাইগ্রেশন পাথগুলি সংজ্ঞায়িত করেন, তখন আপনি কিছু সংস্করণের জন্য স্বয়ংক্রিয় মাইগ্রেশন এবং অন্যদের জন্য ম্যানুয়াল মাইগ্রেশন ব্যবহার করতে পারেন৷ আপনি যদি একই সংস্করণের জন্য একটি স্বয়ংক্রিয় মাইগ্রেশন এবং একটি ম্যানুয়াল মাইগ্রেশন উভয়কেই সংজ্ঞায়িত করেন, তাহলে রুমটি ম্যানুয়াল মাইগ্রেশন ব্যবহার করে।

টেস্ট মাইগ্রেশন

মাইগ্রেশন প্রায়ই জটিল হয় এবং একটি ভুলভাবে সংজ্ঞায়িত মাইগ্রেশন আপনার অ্যাপ ক্র্যাশ করতে পারে। আপনার অ্যাপের স্থায়িত্ব রক্ষা করতে, আপনার মাইগ্রেশন পরীক্ষা করুন। রুম স্বয়ংক্রিয় এবং ম্যানুয়াল মাইগ্রেশন উভয়ের জন্য পরীক্ষার প্রক্রিয়াতে সহায়তা করার জন্য একটি room-testing মাভেন আর্টিফ্যাক্ট সরবরাহ করে। এই শিল্পকর্মটি কাজ করার জন্য, আপনাকে প্রথমে আপনার ডাটাবেসের স্কিমা রপ্তানি করতে হবে।

স্কিম রপ্তানি করুন

রুম কম্পাইলের সময় আপনার ডাটাবেসের স্কিমা তথ্য একটি JSON ফাইলে রপ্তানি করতে পারে। রপ্তানি করা JSON ফাইলগুলি আপনার ডাটাবেসের স্কিমা ইতিহাসকে উপস্থাপন করে। আপনার সংস্করণ নিয়ন্ত্রণ সিস্টেমে এই ফাইলগুলি সংরক্ষণ করুন যাতে রুম পরীক্ষার উদ্দেশ্যে এবং স্বয়ংক্রিয়-মাইগ্রেশন জেনারেশন সক্ষম করতে ডাটাবেসের নিম্ন সংস্করণ তৈরি করতে পারে৷

রুম গ্রেডল প্লাগইন ব্যবহার করে স্কিমা অবস্থান সেট করুন

আপনি যদি রুম সংস্করণ 2.6.0 বা উচ্চতর ব্যবহার করেন তবে আপনি রুম গ্রেডল প্লাগইন প্রয়োগ করতে পারেন এবং স্কিমা ডিরেক্টরি নির্দিষ্ট করতে room এক্সটেনশন ব্যবহার করতে পারেন।

গ্রোভি

plugins {
  id 'androidx.room'
}

room {
  schemaDirectory "$projectDir/schemas"
}

কোটলিন

plugins {
  id("androidx.room")
}

room {
  schemaDirectory("$projectDir/schemas")
}

যদি আপনার ডাটাবেস স্কিমা ভেরিয়েন্ট, ফ্লেভার বা বিল্ড টাইপের উপর ভিত্তি করে আলাদা হয়, তাহলে আপনাকে অবশ্যই schemaDirectory() কনফিগারেশনটি একাধিকবার ব্যবহার করে বিভিন্ন অবস্থান নির্দিষ্ট করতে হবে, প্রতিটিতে একটি variantMatchName প্রথম আর্গুমেন্ট হিসাবে। প্রতিটি কনফিগারেশন বৈকল্পিক নামের সাথে সহজ তুলনার ভিত্তিতে এক বা একাধিক ভেরিয়েন্টের সাথে মেলে।

নিশ্চিত করুন যে এগুলি সম্পূর্ণ এবং সমস্ত রূপ কভার করে৷ অন্যান্য কনফিগারেশনের সাথে মেলে না এমন ভেরিয়েন্টগুলি পরিচালনা করতে আপনি একটি variantMatchName ছাড়া একটি schemaDirectory() অন্তর্ভুক্ত করতে পারেন৷ উদাহরণস্বরূপ, দুটি বিল্ড ফ্লেভার demo এবং full এবং দুটি বিল্ড প্রকার debug এবং release সহ একটি অ্যাপে, নিম্নলিখিতগুলি বৈধ কনফিগারেশন:

গ্রোভি

room {
  // Applies to 'demoDebug' only
  schemaLocation "demoDebug", "$projectDir/schemas/demoDebug"

  // Applies to 'demoDebug' and 'demoRelease'
  schemaLocation "demo", "$projectDir/schemas/demo"

  // Applies to 'demoDebug' and 'fullDebug'
  schemaLocation "debug", "$projectDir/schemas/debug"

  // Applies to variants that aren't matched by other configurations.
  schemaLocation "$projectDir/schemas"
}

কোটলিন

room {
  // Applies to 'demoDebug' only
  schemaLocation("demoDebug", "$projectDir/schemas/demoDebug")

  // Applies to 'demoDebug' and 'demoRelease'
  schemaLocation("demo", "$projectDir/schemas/demo")

  // Applies to 'demoDebug' and 'fullDebug'
  schemaLocation("debug", "$projectDir/schemas/debug")

  // Applies to variants that aren't matched by other configurations.
  schemaLocation("$projectDir/schemas")
}

টীকা প্রসেসর বিকল্প ব্যবহার করে স্কিমা অবস্থান সেট করুন

আপনি যদি রুম এর 2.5.2 বা তার নীচের সংস্করণ ব্যবহার করেন বা আপনি যদি রুম গ্রেডল প্লাগইন ব্যবহার না করেন তবে room.schemaLocation টীকা প্রসেসর বিকল্পটি ব্যবহার করে স্কিমা অবস্থান সেট করুন।

এই ডিরেক্টরির ফাইলগুলি কিছু Gradle কাজের জন্য ইনপুট এবং আউটপুট হিসাবে ব্যবহৃত হয়। ক্রমবর্ধমান এবং ক্যাশে বিল্ডগুলির সঠিকতা এবং কার্যকারিতার জন্য, আপনাকে অবশ্যই গ্র্যাডলের CommandLineArgumentProvider ব্যবহার করতে হবে যাতে এই ডিরেক্টরি সম্পর্কে Gradle কে অবহিত করা যায়।

প্রথমে, আপনার মডিউলের Gradle বিল্ড ফাইলে নীচে দেখানো RoomSchemaArgProvider ক্লাসটি অনুলিপি করুন। নমুনা ক্লাসে asArguments() পদ্ধতিটি room.schemaLocation=${schemaDir.path} KSP পাস করে। আপনি যদি KAPT এবং javac ব্যবহার করেন, তাহলে এই মানটিকে বদলে -Aroom.schemaLocation=${schemaDir.path} করুন।

গ্রোভি

class RoomSchemaArgProvider implements CommandLineArgumentProvider {

  @InputDirectory
  @PathSensitive(PathSensitivity.RELATIVE)
  File schemaDir

  RoomSchemaArgProvider(File schemaDir) {
    this.schemaDir = schemaDir
  }

  @Override
  Iterable<String> asArguments() {
    // Note: If you're using KAPT and javac, change the line below to
    // return ["-Aroom.schemaLocation=${schemaDir.path}".toString()].
    return ["room.schemaLocation=${schemaDir.path}".toString()]
  }
}

কোটলিন

class RoomSchemaArgProvider(
  @get:InputDirectory
  @get:PathSensitive(PathSensitivity.RELATIVE)
  val schemaDir: File
) : CommandLineArgumentProvider {

  override fun asArguments(): Iterable<String> {
    // Note: If you're using KAPT and javac, change the line below to
    // return listOf("-Aroom.schemaLocation=${schemaDir.path}").
    return listOf("room.schemaLocation=${schemaDir.path}")
  }
}

তারপর নির্দিষ্ট স্কিমা ডিরেক্টরির সাথে RoomSchemaArgProvider ব্যবহার করার জন্য কম্পাইল বিকল্পগুলি কনফিগার করুন:

গ্রোভি

// For KSP, configure using KSP extension:
ksp {
  arg(new RoomSchemaArgProvider(new File(projectDir, "schemas")))
}

// For javac or KAPT, configure using android DSL:
android {
  ...
  defaultConfig {
    javaCompileOptions {
      annotationProcessorOptions {
        compilerArgumentProviders(
          new RoomSchemaArgProvider(new File(projectDir, "schemas"))
        )
      }
    }
  }
}

কোটলিন

// For KSP, configure using KSP extension:
ksp {
  arg(RoomSchemaArgProvider(File(projectDir, "schemas")))
}

// For javac or KAPT, configure using android DSL:
android {
  ...
  defaultConfig {
    javaCompileOptions {
      annotationProcessorOptions {
        compilerArgumentProviders(
          RoomSchemaArgProvider(File(projectDir, "schemas"))
        )
      }
    }
  }
}

একটি একক স্থানান্তর পরীক্ষা করুন

আপনি আপনার মাইগ্রেশন পরীক্ষা করার আগে, আপনার পরীক্ষা নির্ভরতায় রুম থেকে androidx.room:room-testing Maven আর্টিফ্যাক্ট যোগ করুন এবং একটি সম্পদ ফোল্ডার হিসাবে এক্সপোর্ট করা স্কিমার অবস্থান যোগ করুন:

build.gradle

গ্রোভি

android {
    ...
    sourceSets {
        // Adds exported schema location as test app assets.
        androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
    }
}

dependencies {
    ...
    androidTestImplementation "androidx.room:room-testing:2.6.1"
}

কোটলিন

android {
    ...
    sourceSets {
        // Adds exported schema location as test app assets.
        getByName("androidTest").assets.srcDir("$projectDir/schemas")
    }
}

dependencies {
    ...
    testImplementation("androidx.room:room-testing:2.6.1")
}

টেস্টিং প্যাকেজ একটি MigrationTestHelper ক্লাস প্রদান করে, যা এক্সপোর্ট করা স্কিমা ফাইল পড়তে পারে। প্যাকেজটি JUnit4 TestRule ইন্টারফেসও প্রয়োগ করে, তাই এটি তৈরি করা ডাটাবেসগুলি পরিচালনা করতে পারে।

নিম্নলিখিত উদাহরণটি একটি একক মাইগ্রেশনের জন্য একটি পরীক্ষা প্রদর্শন করে:

কোটলিন

@RunWith(AndroidJUnit4::class)
class MigrationTest {
    private val TEST_DB = "migration-test"

    @get:Rule
    val helper: MigrationTestHelper = MigrationTestHelper(
            InstrumentationRegistry.getInstrumentation(),
            MigrationDb::class.java.canonicalName,
            FrameworkSQLiteOpenHelperFactory()
    )

    @Test
    @Throws(IOException::class)
    fun migrate1To2() {
        var db = helper.createDatabase(TEST_DB, 1).apply {
            // Database has schema version 1. Insert some data using SQL queries.
            // You can't use DAO classes because they expect the latest schema.
            execSQL(...)

            // Prepare for the next version.
            close()
        }

        // Re-open the database with version 2 and provide
        // MIGRATION_1_2 as the migration process.
        db = helper.runMigrationsAndValidate(TEST_DB, 2, true, MIGRATION_1_2)

        // MigrationTestHelper automatically verifies the schema changes,
        // but you need to validate that the data was migrated properly.
    }
}

জাভা

@RunWith(AndroidJUnit4.class)
public class MigrationTest {
    private static final String TEST_DB = "migration-test";

    @Rule
    public MigrationTestHelper helper;

    public MigrationTest() {
        helper = new MigrationTestHelper(InstrumentationRegistry.getInstrumentation(),
                MigrationDb.class.getCanonicalName(),
                new FrameworkSQLiteOpenHelperFactory());
    }

    @Test
    public void migrate1To2() throws IOException {
        SupportSQLiteDatabase db = helper.createDatabase(TEST_DB, 1);

        // Database has schema version 1. Insert some data using SQL queries.
        // You can't use DAO classes because they expect the latest schema.
        db.execSQL(...);

        // Prepare for the next version.
        db.close();

        // Re-open the database with version 2 and provide
        // MIGRATION_1_2 as the migration process.
        db = helper.runMigrationsAndValidate(TEST_DB, 2, true, MIGRATION_1_2);

        // MigrationTestHelper automatically verifies the schema changes,
        // but you need to validate that the data was migrated properly.
    }
}

সমস্ত মাইগ্রেশন পরীক্ষা করুন

যদিও এটি একটি একক বর্ধিত স্থানান্তর পরীক্ষা করা সম্ভব, আমরা সুপারিশ করি যে আপনি একটি পরীক্ষা অন্তর্ভুক্ত করুন যা আপনার অ্যাপের ডাটাবেসের জন্য সংজ্ঞায়িত সমস্ত স্থানান্তরকে কভার করে৷ এটি নিশ্চিত করতে সাহায্য করে যে সম্প্রতি তৈরি করা ডাটাবেস দৃষ্টান্ত এবং সংজ্ঞায়িত মাইগ্রেশন পাথ অনুসরণকারী একটি পুরানো উদাহরণের মধ্যে কোন পার্থক্য নেই।

নিম্নলিখিত উদাহরণটি সমস্ত সংজ্ঞায়িত মাইগ্রেশনের জন্য একটি পরীক্ষা প্রদর্শন করে:

কোটলিন

@RunWith(AndroidJUnit4::class)
class MigrationTest {
    private val TEST_DB = "migration-test"

    // Array of all migrations.
    private val ALL_MIGRATIONS = arrayOf(
            MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4)

    @get:Rule
    val helper: MigrationTestHelper = MigrationTestHelper(
            InstrumentationRegistry.getInstrumentation(),
            AppDatabase::class.java.canonicalName,
            FrameworkSQLiteOpenHelperFactory()
    )

    @Test
    @Throws(IOException::class)
    fun migrateAll() {
        // Create earliest version of the database.
        helper.createDatabase(TEST_DB, 1).apply {
            close()
        }

        // Open latest version of the database. Room validates the schema
        // once all migrations execute.
        Room.databaseBuilder(
            InstrumentationRegistry.getInstrumentation().targetContext,
            AppDatabase::class.java,
            TEST_DB
        ).addMigrations(*ALL_MIGRATIONS).build().apply {
            openHelper.writableDatabase.close()
        }
    }
}

জাভা

@RunWith(AndroidJUnit4.class)
public class MigrationTest {
    private static final String TEST_DB = "migration-test";

    @Rule
    public MigrationTestHelper helper;

    public MigrationTest() {
        helper = new MigrationTestHelper(InstrumentationRegistry.getInstrumentation(),
                AppDatabase.class.getCanonicalName(),
                new FrameworkSQLiteOpenHelperFactory());
    }

    @Test
    public void migrateAll() throws IOException {
        // Create earliest version of the database.
        SupportSQLiteDatabase db = helper.createDatabase(TEST_DB, 1);
        db.close();

        // Open latest version of the database. Room validates the schema
        // once all migrations execute.
        AppDatabase appDb = Room.databaseBuilder(
                InstrumentationRegistry.getInstrumentation().getTargetContext(),
                AppDatabase.class,
                TEST_DB)
                .addMigrations(ALL_MIGRATIONS).build();
        appDb.getOpenHelper().getWritableDatabase();
        appDb.close();
    }

    // Array of all migrations.
    private static final Migration[] ALL_MIGRATIONS = new Migration[]{
            MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4};
}

অনুপস্থিত মাইগ্রেশন পাথগুলি সুন্দরভাবে পরিচালনা করুন

যদি রুম বর্তমান সংস্করণে একটি ডিভাইসে বিদ্যমান ডাটাবেস আপগ্রেড করার জন্য একটি মাইগ্রেশন পথ খুঁজে না পায়, তাহলে একটি IllegalStateException ঘটে। মাইগ্রেশন পাথ অনুপস্থিত থাকলে বিদ্যমান ডেটা হারানো যদি গ্রহণযোগ্য হয়, আপনি ডাটাবেস তৈরি করার সময় fallbackToDestructiveMigration() বিল্ডার পদ্ধতিতে কল করুন:

কোটলিন

Room.databaseBuilder(applicationContext, MyDb::class.java, "database-name")
        .fallbackToDestructiveMigration()
        .build()

জাভা

Room.databaseBuilder(getApplicationContext(), MyDb.class, "database-name")
        .fallbackToDestructiveMigration()
        .build();

এই পদ্ধতিটি রুমকে আপনার অ্যাপের ডাটাবেসের সারণীগুলিকে ধ্বংসাত্মকভাবে পুনরায় তৈরি করতে বলে যখন এটি একটি ক্রমবর্ধমান মাইগ্রেশন সঞ্চালন করতে হবে এবং কোন সংজ্ঞায়িত মাইগ্রেশন পথ নেই।

আপনি যদি শুধুমাত্র কিছু পরিস্থিতিতে ধ্বংসাত্মক বিনোদনে ফিরে যেতে চান, fallbackToDestructiveMigration() এর কয়েকটি বিকল্প রয়েছে :

  • যদি আপনার স্কিমা ইতিহাসের নির্দিষ্ট সংস্করণগুলি এমন ত্রুটির কারণ হয় যা আপনি মাইগ্রেশন পাথগুলির সাথে সমাধান করতে পারবেন না, তাহলে এর পরিবর্তে fallbackToDestructiveMigrationFrom() ব্যবহার করুন৷ এই পদ্ধতিটি নির্দেশ করে যে আপনি নির্দিষ্ট সংস্করণ থেকে স্থানান্তরিত করার সময় শুধুমাত্র রুম ধ্বংসাত্মক বিনোদনে ফিরে যেতে চান।
  • উচ্চতর ডাটাবেস সংস্করণ থেকে নিম্ন সংস্করণে স্থানান্তরিত করার সময় যদি আপনি রুমটি ধ্বংসাত্মক বিনোদনে ফিরে যেতে চান তবে এর পরিবর্তে fallbackToDestructiveMigrationOnDowngrade() ব্যবহার করুন।

রুম 2.2.0 এ আপগ্রেড করার সময় কলাম ডিফল্ট মানগুলি পরিচালনা করুন

রুম 2.2.0 এবং উচ্চতর, আপনি @ColumnInfo(defaultValue = "...") টীকা ব্যবহার করে একটি কলামের জন্য একটি ডিফল্ট মান নির্ধারণ করতে পারেন। 2.2.0-এর চেয়ে কম সংস্করণে, একটি কলামের জন্য একটি ডিফল্ট মান নির্ধারণ করার একমাত্র উপায় হল এটি সরাসরি একটি কার্যকর করা SQL স্টেটমেন্টে সংজ্ঞায়িত করা, যা একটি ডিফল্ট মান তৈরি করে যা রুম জানে না। এর মানে হল যে যদি একটি ডাটাবেস মূলত 2.2.0-এর কম রুমের সংস্করণ দ্বারা তৈরি করা হয়, তাহলে রুম 2.2.0 ব্যবহার করার জন্য আপনার অ্যাপকে আপগ্রেড করার জন্য আপনাকে রুম API ব্যবহার না করে আপনার সংজ্ঞায়িত বিদ্যমান ডিফল্ট মানগুলির জন্য একটি বিশেষ স্থানান্তর পথ প্রদান করতে হতে পারে।

উদাহরণস্বরূপ, ধরুন একটি ডাটাবেসের সংস্করণ 1 একটি Song সত্তাকে সংজ্ঞায়িত করে:

কোটলিন

// Song entity, database version 1, Room 2.1.0.
@Entity
data class Song(
    @PrimaryKey
    val id: Long,
    val title: String
)

জাভা

// Song entity, database version 1, Room 2.1.0.
@Entity
public class Song {
    @PrimaryKey
    final long id;
    final String title;
}

ধরুন একই ডাটাবেসের সংস্করণ 2 একটি নতুন NOT NULL কলাম যোগ করে এবং সংস্করণ 1 থেকে সংস্করণ 2 এ একটি মাইগ্রেশন পথ সংজ্ঞায়িত করে:

কোটলিন

// Song entity, database version 2, Room 2.1.0.
@Entity
data class Song(
    @PrimaryKey
    val id: Long,
    val title: String,
    val tag: String // Added in version 2.
)

// Migration from 1 to 2, Room 2.1.0.
val MIGRATION_1_2 = object : Migration(1, 2) {
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL(
            "ALTER TABLE Song ADD COLUMN tag TEXT NOT NULL DEFAULT ''")
    }
}

জাভা

// Song entity, database version 2, Room 2.1.0.
@Entity
public class Song {
    @PrimaryKey
    final long id;
    final String title;
    @NonNull
    final String tag; // Added in version 2.
}


// Migration from 1 to 2, Room 2.1.0.
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        database.execSQL(
            "ALTER TABLE Song ADD COLUMN tag TEXT NOT NULL DEFAULT ''");
    }
};

এটি অ্যাপের আপডেট এবং নতুন ইনস্টলের মধ্যে অন্তর্নিহিত সারণীতে একটি পার্থক্য সৃষ্টি করে। যেহেতু tag কলামের ডিফল্ট মান শুধুমাত্র সংস্করণ 1 থেকে সংস্করণ 2-এ মাইগ্রেশন পাথে ঘোষণা করা হয়েছে, যে কোনও ব্যবহারকারী যারা সংস্করণ 2 থেকে শুরু করে অ্যাপটি ইনস্টল করেন তাদের ডাটাবেস স্কিমাতে tag জন্য ডিফল্ট মান থাকে না।

2.2.0-এর চেয়ে কম রুমের সংস্করণগুলিতে, এই অসঙ্গতিটি ক্ষতিকারক নয়৷ যাইহোক, যদি অ্যাপটি পরে রুম 2.2.0 বা উচ্চতর ব্যবহার করার জন্য আপগ্রেড করে এবং @ColumnInfo টীকা ব্যবহার করে tag জন্য একটি ডিফল্ট মান অন্তর্ভুক্ত করতে Song সত্তা শ্রেণীতে পরিবর্তন করে, তাহলে রুম এই অসঙ্গতি দেখতে পাবে। এর ফলে স্কিমা যাচাইকরণ ব্যর্থ হয়।

আপনার আগের মাইগ্রেশন পাথে যখন কলাম ডিফল্ট মান ঘোষণা করা হয় তখন ডাটাবেস স্কিমা সমস্ত ব্যবহারকারীদের মধ্যে সামঞ্জস্যপূর্ণ হয় তা নিশ্চিত করতে সাহায্য করার জন্য, আপনি প্রথমবার রুম 2.2.0 বা উচ্চতর ব্যবহার করার জন্য আপনার অ্যাপ আপগ্রেড করার সময় নিম্নলিখিতগুলি করুন:

  1. @ColumnInfo টীকা ব্যবহার করে তাদের নিজ নিজ সত্তা ক্লাসে কলামের ডিফল্ট মান ঘোষণা করুন।
  2. ডাটাবেস সংস্করণ সংখ্যা 1 দ্বারা বৃদ্ধি করুন।
  3. বিদ্যমান কলামে প্রয়োজনীয় ডিফল্ট মান যোগ করার জন্য ড্রপ এবং পুনরায় তৈরি করার কৌশল প্রয়োগ করে নতুন সংস্করণে একটি মাইগ্রেশন পথ সংজ্ঞায়িত করুন।

নিম্নলিখিত উদাহরণ এই প্রক্রিয়া প্রদর্শন করে:

কোটলিন

// Migration from 2 to 3, Room 2.2.0.
val MIGRATION_2_3 = object : Migration(2, 3) {
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL("""
                CREATE TABLE new_Song (
                    id INTEGER PRIMARY KEY NOT NULL,
                    name TEXT,
                    tag TEXT NOT NULL DEFAULT ''
                )
                """.trimIndent())
        database.execSQL("""
                INSERT INTO new_Song (id, name, tag)
                SELECT id, name, tag FROM Song
                """.trimIndent())
        database.execSQL("DROP TABLE Song")
        database.execSQL("ALTER TABLE new_Song RENAME TO Song")
    }
}

জাভা

// Migration from 2 to 3, Room 2.2.0.
static final Migration MIGRATION_2_3 = new Migration(2, 3) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        database.execSQL("CREATE TABLE new_Song (" +
                "id INTEGER PRIMARY KEY NOT NULL," +
                "name TEXT," +
                "tag TEXT NOT NULL DEFAULT '')");
        database.execSQL("INSERT INTO new_Song (id, name, tag) " +
                "SELECT id, name, tag FROM Song");
        database.execSQL("DROP TABLE Song");
        database.execSQL("ALTER TABLE new_Song RENAME TO Song");
    }
};