रूम डेटाबेस को माइग्रेट करना

अपने ऐप्लिकेशन में सुविधाएं जोड़ने और उनमें बदलाव करने पर, आपको रूम की इकाई में बदलाव करना होगा क्लास और डेटाबेस टेबल का भी इस्तेमाल करें. यह ज़रूरी है उपयोगकर्ता के उस डेटा को सुरक्षित रखने के लिए जो पहले से ही डिवाइस के डेटाबेस में मौजूद है अपडेट से डेटाबेस स्कीमा में बदलाव होता है.

माइग्रेशन के लिए, चैट रूम में ऑटोमेटेड और मैन्युअल, दोनों विकल्प इस्तेमाल किए जा सकते हैं. अपने-आप माइग्रेशन होने की सुविधा, स्कीमा में होने वाले ज़्यादातर बुनियादी बदलावों के लिए काम करती है. हालांकि, आपको ऐसा करना पड़ सकता है ज़्यादा जटिल बदलावों के लिए, माइग्रेशन पाथ को मैन्युअल तौर पर तय करने की सुविधा मिलती है.

डेटा को अपने-आप दूसरी जगह भेजने की सुविधा

दो डेटाबेस वर्शन के बीच अपने-आप होने वाले माइग्रेशन की घोषणा करने के लिए, @AutoMigration के लिए एनोटेशन autoMigrations प्रॉपर्टी @Database में है:

Kotlin

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

Java

// 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 का इस्तेमाल करके, रूम को अतिरिक्त जानकारी दी जा सकती है सही तरीके से माइग्रेशन पाथ जनरेट करने की ज़रूरत है. ऐसी स्टैटिक क्लास तय करें जो AutoMigrationSpec को आपकी RoomDatabase क्लास में लागू करता है और इसकी व्याख्या करता है इनमें से एक या ज़्यादा:

अपने-आप होने वाले माइग्रेशन के लिए, AutoMigrationSpec को लागू करने की सुविधा का इस्तेमाल करने के लिए, इसे सेट करें spec प्रॉपर्टी से जुड़े @AutoMigration एनोटेशन में:

Kotlin

@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
  ...
}

Java

@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 क्लास, माइग्रेशन पाथ को साफ़ तौर पर startVersion और endVersion को Migration.migrate() तरीका. इनका इस्तेमाल करके, अपने डेटाबेस बिल्डर में Migration क्लास जोड़ें यह addMigrations() तरीका:

Kotlin

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

Java

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 के लिए मैन्युअल तरीके का इस्तेमाल किया जाता है. माइग्रेशन.

माइग्रेशन की जांच करें

माइग्रेशन अक्सर जटिल होता है और गलत तरीके से परिभाषित माइग्रेशन की वजह से आपका ऐप्लिकेशन क्रैश हो जाए. अपने ऐप्लिकेशन को ठीक से काम करते रहने के लिए, उसकी जांच करें माइग्रेशन. रूम, room-testing Maven आर्टफ़ैक्ट उपलब्ध कराता है, ताकि ऑटोमेटेड और मैन्युअल, दोनों माइग्रेशन के लिए टेस्टिंग प्रोसेस करता है. इस आर्टफ़ैक्ट के लिए काम करता है, तो पहले आपको अपने डेटाबेस का स्कीमा एक्सपोर्ट करना होगा.

स्कीमा एक्सपोर्ट करें

रूम आपके डेटाबेस की स्कीमा जानकारी को कंपाइल करते समय एक JSON फ़ाइल में एक्सपोर्ट कर सकता है समय. एक्सपोर्ट की गई JSON फ़ाइलें, आपके डेटाबेस का स्कीमा इतिहास दिखाती हैं. स्टोर इन फ़ाइलों को आपके वर्शन कंट्रोल सिस्टम में अपलोड कर सकता है, ताकि रूम इस डेटाबेस का इस्तेमाल टेस्टिंग के लिए और अपने-आप माइग्रेशन जनरेट करने की सुविधा चालू करने के लिए किया जा सकता है.

रूम Gradle प्लग इन का इस्तेमाल करके स्कीमा की जगह सेट करें

अगर आप रूम का 2.6.0 या इसके बाद वाला वर्शन इस्तेमाल कर रहे हैं, तो रूम Gradle प्लग इन और स्कीमा डायरेक्ट्री तय करने के लिए room एक्सटेंशन.

ग्रूवी

plugins {
  id 'androidx.room'
}

room {
  schemaDirectory "$projectDir/schemas"
}

Kotlin

plugins {
  id("androidx.room")
}

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

अगर आपका डेटाबेस स्कीमा, वैरिएंट, फ़्लेवर या बिल्ड के आधार पर अलग-अलग है प्रकार है, तो आपको schemaDirectory() का उपयोग करके अलग-अलग स्थान बताने होंगे कॉन्फ़िगरेशन को कई बार कॉन्फ़िगर किया गया है. हर कॉन्फ़िगरेशन में variantMatchName पहले है तर्क है. हर कॉन्फ़िगरेशन, सामान्य सेटिंग के आधार पर एक या उससे ज़्यादा वैरिएंट से मैच कर सकता है वैरिएंट के नाम से तुलना.

पक्का करें कि इनमें सभी वैरिएंट शामिल हों और इनमें सभी वैरिएंट शामिल हों. आप यह भी शामिल कर सकते हैं जो वैरिएंट मैच नहीं करते उन्हें मैनेज करने के लिए, variantMatchName के बिना schemaDirectory() में से किसी एक के मुताबिक काम करता है. उदाहरण के लिए, दो बिल्ड वाले ऐप्लिकेशन में demo और full फ़्लेवर वाला है. साथ ही, दो बिल्ड टाइप debug और release हैं, ये कॉन्फ़िगरेशन मान्य हैं:

ग्रूवी

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

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

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

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

Kotlin

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

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

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

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

एनोटेशन प्रोसेसर विकल्प का इस्तेमाल करके, स्कीमा की जगह की जानकारी सेट करें

अगर आप Room के 2.5.2 या इससे पहले के वर्शन का इस्तेमाल कर रहे हैं या रूम Gradle प्लग इन, room.schemaLocation का इस्तेमाल करके स्कीमा की जगह सेट करें एनोटेशन प्रोसेसर विकल्प.

इस डायरेक्ट्री की फ़ाइलों का इस्तेमाल, कुछ Gradle टास्क के लिए, इनपुट और आउटपुट के तौर पर किया जाता है. इंक्रीमेंटल और कैश मेमोरी में सेव किए गए बिल्ड को सटीक बनाने और परफ़ॉर्मेंस बेहतर करने के लिए, आपको इनका इस्तेमाल करना चाहिए ग्रेडल CommandLineArgumentProvider Gradle को इस डायरेक्ट्री के बारे में जानकारी देना.

सबसे पहले, नीचे दिखाई गई RoomSchemaArgProvider क्लास को अपने मॉड्यूल के Gradle बिल्ड फ़ाइल. सैंपल क्लास में asArguments() तरीका पास हुआ KSP के लिए room.schemaLocation=${schemaDir.path}. अगर आप 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()]
  }
}

Kotlin

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"))
        )
      }
    }
  }
}

Kotlin

// 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 आर्टफ़ैक्ट शामिल है डिपेंडेंसी चुनें और एक्सपोर्ट किए गए स्कीमा की जगह को ऐसेट फ़ोल्डर के तौर पर जोड़ें:

बिल्ड.ग्रेडल

ग्रूवी

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"
}

Kotlin

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 क्लास का इस्तेमाल करती है, जो एक्सपोर्ट की गई स्कीमा फ़ाइलों को पढ़ सकती है. पैकेज, जेयूनिट4 TestRule इंटरफ़ेस में जोड़ दिया जाता है, ताकि यह बनाए गए डेटाबेस को मैनेज कर सके.

यहां दिए गए उदाहरण में, एक माइग्रेशन के लिए टेस्ट दिखाया गया है:

Kotlin

@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.
    }
}

Java

@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.
    }
}

सभी माइग्रेशन की जांच करें

हालांकि, माइग्रेशन के लिए एक इंक्रीमेंटल (बढ़ने वाले) माइग्रेशन का टेस्ट किया जा सकता है. हमारा सुझाव है कि कि आप ऐसा टेस्ट शामिल करें जिसमें आपके ऐप्लिकेशन के लिए तय किए गए सभी माइग्रेशन शामिल हों डेटाबेस. इससे यह पक्का करने में मदद मिलती है कि हाल ही में बनाए गए तय माइग्रेशन के बाद डेटाबेस इंस्टेंस और पुराना इंस्टेंस पाथ.

नीचे दिए गए उदाहरण में, सभी तय माइग्रेशन के लिए टेस्ट दिखाया गया है:

Kotlin

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

Java

@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() बिल्डर तरीके का इस्तेमाल करें:

Kotlin

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

Java

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

इस तरीके से रूम को आपके ऐप्लिकेशन में टेबल को फिर से बनाने के लिए कहा जाता है डेटाबेस जब उसे इंक्रीमेंटल माइग्रेशन करने की ज़रूरत होती है और तय माइग्रेशन पाथ.

अगर आप कमरा बुक करना चाहते हैं, तो कुछ समय के लिए fallbackToDestructiveMigration() के कुछ विकल्प मौजूद हैं:

  • अगर आपके स्कीमा इतिहास के खास वर्शन की वजह से ऐसी गड़बड़ियां होती हैं जिन्हें आप ठीक नहीं कर सकते माइग्रेशन पाथ के साथ fallbackToDestructiveMigrationFrom() आज़माएं. यह तरीका बताता है कि आप चाहते हैं कि कमरा वापस खराब हो जाए मनोरंजन के लिए इस्तेमाल किया जाता है.
  • क्या आप चाहते हैं कि माइग्रेट करते समय कमरे में फिर से नुकसान पहुंचाने वाले मनोरंजन का इंतज़ाम हो डेटाबेस के उच्च वर्शन से निचले वर्शन की ओर ले जाते हैं, तो fallbackToDestructiveMigrationOnDowngrade() आज़माएं.

रूम 2.2.0 में अपग्रेड करने पर, कॉलम की डिफ़ॉल्ट वैल्यू मैनेज करना

रूम 2.2.0 और उसके बाद के वर्शन में, किसी कॉलम के लिए डिफ़ॉल्ट वैल्यू तय करने के लिए, व्याख्या @ColumnInfo(defaultValue = "..."). 2.2.0 से पहले के वर्शन में, कॉलम को सीधे एक निष्पादित SQL स्टेटमेंट में परिभाषित किया जाता है, जो एक वह डिफ़ॉल्ट वैल्यू है जिसके बारे में रूम को पता नहीं है. इसका मतलब है कि अगर कोई डेटाबेस इसे मूल रूप से Room के 2.2.0 से पहले के वर्शन से बनाया गया है. इसलिए, आपका ऐप्लिकेशन रूम 2.2.0 का इस्तेमाल करने के लिए, आपको रूम एपीआई का इस्तेमाल किए बिना तय की गई मौजूदा डिफ़ॉल्ट वैल्यू.

उदाहरण के लिए, मान लें कि डेटाबेस का वह वर्शन 1 किसी Song इकाई के बारे में बताता है:

Kotlin

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

Java

// 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 तक माइग्रेशन पाथ के बारे में बताता है:

Kotlin

// 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 ''")
    }
}

Java

// 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 तक माइग्रेशन पथ में बताया गया, तो दूसरे वर्शन से शुरू होने वाले ऐप्लिकेशन को इंस्टॉल करने के लिए, tag की डिफ़ॉल्ट वैल्यू सेट नहीं की जाती कर सकते हैं.

रूम के 2.2.0 से पहले के वर्शन में, यह अंतर नुकसान नहीं पहुंचाता है. हालांकि, अगर ऐप्लिकेशन, रूम 2.2.0 या उसके बाद के वर्शन का इस्तेमाल करने के लिए, बाद में अपग्रेड करता है और Song इकाई को बदल देता है क्लास का इस्तेमाल करें, ताकि tag के लिए डिफ़ॉल्ट वैल्यू शामिल की जा सके. @ColumnInfo एनोटेशन, रूम तो इस अंतर को देख सकते हैं. इस वजह से स्कीमा विफल हो जाता है पुष्टि करनी होगी.

यह पक्का करने में मदद करने के लिए कि कॉलम में डाले जाने पर, डेटाबेस स्कीमा सभी उपयोगकर्ताओं के लिए एक जैसा हो डिफ़ॉल्ट वैल्यू का एलान आपके पिछले माइग्रेशन पाथ में किया जाता है. इसलिए, ये करें रूम 2.2.0 या उसके बाद के वर्शन का इस्तेमाल करने के लिए, पहली बार अपने ऐप्लिकेशन को अपग्रेड करने पर:

  1. इसका इस्तेमाल करके कॉलम की डिफ़ॉल्ट वैल्यू को उनसे जुड़ी इकाई की क्लास में बताएं @ColumnInfo एनोटेशन.
  2. डेटाबेस के वर्शन की संख्या को 1 से बढ़ाएं.
  3. नए वर्शन पर माइग्रेशन का वह पाथ तय करें जो ड्रॉप और रणनीति फिर से बनाएं का इस्तेमाल करें.

यह उदाहरण इस प्रोसेस को दिखाता है:

Kotlin

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

Java

// 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");
    }
};