پایگاه داده اتاق خود را مهاجرت کنید

همانطور که ویژگی‌ها را در برنامه خود اضافه و تغییر می‌دهید، باید کلاس‌های موجودیت اتاق و جداول پایگاه داده زیرین خود را تغییر دهید تا این تغییرات را منعکس کنند. هنگامی که به‌روزرسانی برنامه، طرح پایگاه داده را تغییر می‌دهد، حفظ داده‌های کاربر که از قبل در پایگاه داده روی دستگاه وجود دارد، مهم است.

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

مهاجرت های خودکار

برای اعلام یک انتقال خودکار بین دو نسخه پایگاه داده، یک حاشیه نویسی @AutoMigration به ویژگی autoMigrations در @Database اضافه کنید:

کاتلین

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

مشخصات مهاجرت خودکار

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

  • حذف یا تغییر نام جدول
  • حذف یا تغییر نام یک ستون

می‌توانید از AutoMigrationSpec برای دادن اطلاعات اضافی که برای ایجاد صحیح مسیرهای مهاجرت به اتاق نیاز دارد، استفاده کنید. یک کلاس ثابت تعریف کنید که AutoMigrationSpec را در کلاس RoomDatabase شما پیاده سازی کند و آن را با یک یا چند مورد زیر حاشیه نویسی کنید:

برای استفاده از پیاده سازی AutoMigrationSpec برای انتقال خودکار، ویژگی spec را در حاشیه نویسی @AutoMigration مربوطه تنظیم کنید:

کاتلین

@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 خود پیاده سازی کنید، پس از تکمیل انتقال خودکار، Room آن را فراخوانی می کند.

مهاجرت های دستی

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

یک کلاس Migration به صراحت یک مسیر مهاجرت را بین startVersion و endVersion با نادیده گرفتن متد Migration.migrate() تعریف می کند. کلاس های Migration خود را با استفاده از متد addMigrations() به سازنده پایگاه داده خود اضافه کنید:

کاتلین

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 یک مصنوع Maven room-testing ارائه می دهد تا به فرآیند آزمایش برای مهاجرت های خودکار و دستی کمک کند. برای اینکه این آرتیفکت کار کند، ابتدا باید شمای پایگاه داده خود را صادر کنید.

طرحواره های صادراتی

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

با استفاده از پلاگین Room Gradle مکان طرح را تنظیم کنید

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

شیار

plugins {
  id 'androidx.room'
}

room {
  schemaDirectory "$projectDir/schemas"
}

کاتلین

plugins {
  id("androidx.room")
}

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

اگر شمای پایگاه داده شما بر اساس نوع، طعم یا نوع ساخت متفاوت است، باید مکان های مختلف را با استفاده از پیکربندی schemaDirectory() چندین بار مشخص کنید، که هر کدام یک variantMatchName به عنوان اولین آرگومان دارد. هر پیکربندی می تواند یک یا چند نوع را بر اساس مقایسه ساده با نام گونه مطابقت دهد.

مطمئن شوید که اینها جامع هستند و همه انواع را پوشش می دهند. همچنین می‌توانید یک schemaDirectory() بدون variantMatchName برای مدیریت انواعی که با هیچ یک از پیکربندی‌های دیگر مطابقت ندارند، اضافه کنید. به عنوان مثال، در یک برنامه با دو نوع ساخت نسخه ی 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"
}

کاتلین

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

با استفاده از گزینه پردازشگر حاشیه نویسی مکان طرح را تنظیم کنید

اگر از نسخه 2.5.2 یا پایین‌تر Room استفاده می‌کنید، یا اگر از افزونه Room Gradle استفاده نمی‌کنید، مکان طرح را با استفاده از گزینه room.schemaLocation حاشیه نویسی پردازنده تنظیم کنید.

فایل های این فهرست به عنوان ورودی و خروجی برای برخی از وظایف Gradle استفاده می شود. برای درستی و عملکرد ساخت‌های افزایشی و کش، باید از CommandLineArgumentProvider Gradle برای اطلاع دادن Gradle در مورد این دایرکتوری استفاده کنید.

ابتدا کلاس RoomSchemaArgProvider که در زیر نشان داده شده است را در فایل ساخت Gradle ماژول خود کپی کنید. متد 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"))
        )
      }
    }
  }
}

یک مهاجرت را آزمایش کنید

قبل از اینکه بتوانید مهاجرت‌های خود را آزمایش کنید، آرتیفکت Maven androidx.room:room-testing را از Room به وابستگی‌های آزمایشی خود اضافه کنید و مکان طرحواره صادر شده را به عنوان یک پوشه دارایی اضافه کنید:

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

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

اگر فقط می‌خواهید در موقعیت‌های خاصی به اتاق بازگردید تا به تفریحات مخرب بازگردید، چند گزینه برای fallbackToDestructiveMigration() وجود دارد:

  • اگر نسخه‌های خاصی از تاریخچه طرحواره شما باعث ایجاد خطاهایی می‌شوند که نمی‌توانید آنها را با مسیرهای مهاجرت حل کنید، به جای آن از fallbackToDestructiveMigrationFrom() استفاده کنید. این روش نشان می‌دهد که می‌خواهید اتاق تنها هنگام مهاجرت از نسخه‌های خاص به تفریحات مخرب بازگردد.
  • اگر می‌خواهید که Room تنها زمانی که از یک نسخه پایگاه داده بالاتر به نسخه پایین‌تر مهاجرت می‌کند، به تفریحات مخرب بازگردد، به جای آن از fallbackToDestructiveMigrationOnDowngrade() استفاده کنید.

هنگام ارتقاء به اتاق 2.2.0، مقادیر پیش فرض ستون را مدیریت کنید

در Room 2.2.0 و بالاتر، می توانید با استفاده از حاشیه نویسی @ColumnInfo(defaultValue = "...") یک مقدار پیش فرض برای یک ستون تعریف کنید. در نسخه‌های پایین‌تر از 2.2.0، تنها راه برای تعریف یک مقدار پیش‌فرض برای یک ستون، تعریف مستقیم آن در یک دستور SQL اجرا شده است، که یک مقدار پیش‌فرض ایجاد می‌کند که Room از آن اطلاعی ندارد. این بدان معناست که اگر یک پایگاه داده در اصل توسط نسخه‌ای از Room پایین‌تر از 2.2.0 ایجاد شده باشد، ارتقای برنامه شما برای استفاده از Room 2.2.0 ممکن است از شما نیاز داشته باشد که یک مسیر انتقال ویژه برای مقادیر پیش‌فرض موجودی که بدون استفاده از Room 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 در طرح پایگاه داده خود ندارد.

در نسخه های Room کمتر از 2.2.0، این اختلاف بی ضرر است. با این حال، اگر برنامه بعداً برای استفاده از Room 2.2.0 یا بالاتر ارتقا یابد و کلاس موجودیت Song را تغییر دهد تا با استفاده از حاشیه‌نویسی @ColumnInfo ، یک مقدار پیش‌فرض برای tag اضافه کند، Room می‌تواند این اختلاف را ببیند. این منجر به اعتبارسنجی طرحواره ناموفق می شود.

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

  1. با استفاده از حاشیه نویسی @ColumnInfo مقادیر پیش فرض ستون را در کلاس های موجودیت مربوطه خود اعلام کنید.
  2. شماره نسخه پایگاه داده را 1 افزایش دهید.
  3. یک مسیر انتقال به نسخه جدید تعریف کنید که استراتژی drop and recreate را پیاده سازی می کند تا مقادیر پیش فرض لازم را به ستون های موجود اضافه کند.

مثال زیر این فرآیند را نشان می دهد:

کاتلین

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