عند إضافة ميزات وتغييرها في تطبيقك، عليك تعديل فئات ملف تعريف قاعدة بيانات Room وجداول قاعدة البيانات الأساسية لتعكس هذه التغييرات. من المهم الحفاظ على بيانات المستخدمين التي سبق أن تم تخزينها في قاعدة البيانات على الجهاز عندما يؤدي تحديث التطبيق إلى تغيير مخطّط قاعدة البيانات.
يتيح Room خيارَي النقل المبرمَج والنقل اليدوي لنقل البيانات بشكل تدريجي. تعمل عمليات نقل البيانات التلقائية مع معظم التغييرات الأساسية في المخطط، ولكن قد تحتاج إلى تحديد مسارات نقل البيانات يدويًا لإجراء تغييرات أكثر تعقيدًا.
عمليات نقل البيانات المبرمَجة
لإعلان عملية نقل مبرمَجة بين نسختَين من قاعدة البيانات، أضِف تعليقًا توضيحيًا
@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 { ... }
مواصفات نقل البيانات تلقائيًا
إذا رصد Room تغييرات مخططات غير واضحة وتعذّر عليه إنشاء
خطة نقل بدون مزيد من الإدخال، سيُرسِل خطأ في وقت الترجمة ويطلب منك
تنفيذ
AutoMigrationSpec
.
يحدث ذلك غالبًا عندما يتضمّن نقل البيانات أحد الإجراءات التالية:
- حذف جدول أو إعادة تسميته
- حذف عمود أو إعادة تسميته
يمكنك استخدام AutoMigrationSpec
لتزويد Room بالمعلومات الإضافية التي يحتاج إليها
لإنشاء مسارات نقل البيانات بشكل صحيح. حدِّد فئة ثابتة تُنفِّذ 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
، ستستدعيها Room بعد اكتمال عملية نقل البيانات التلقائية.
عمليات نقل البيانات يدويًا
في الحالات التي تتضمّن عملية نقل البيانات تغييرات معقدة في المخطط، قد لا تتمكّن أداة Room
من إنشاء مسار نقل بيانات مناسب تلقائيًا. على سبيل المثال، إذا قررت хувين البيانات في جدول إلى جدولَين، لا يمكن لتطبيق Room تحديد كيفية إجراء هذا التقسيم. في مثل هذه الحالات، عليك تحديد مسار نقل البيانات يدويًا من خلال تنفيذ فئة
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 عنصر Maven room-testing
للمساعدة في عملية الاختبار لكلّ من عمليات نقل البيانات الآلية واليدوية. لكي يعمل هذا العنصر، يجب أولاً تصدير مخطّط قاعدة بياناتك.
تصدير المخططات
يمكن لواجهة برمجة التطبيقات Room تصدير معلومات مخطّط قاعدة البيانات إلى ملف JSON أثناء عملية compilation. تمثّل ملفات JSON التي تم تصديرها سجلّ مخطّط قاعدة بياناتك. تخزِّن هذه الملفات في نظام التحكّم في الإصدارات حتى تتمكّن Room من إنشاء إصدارات أقل من قاعدة البيانات لأغراض الاختبار وتفعيل إنشاء عملية نقل البيانات التلقائية.
ضبط موقع المخطط باستخدام مكوّن إضافي Gradle في Room
إذا كنت تستخدم الإصدار 2.6.0 من Room أو إصدارًا أحدث، يمكنك تطبيق
Room Gradle Plugin واستخدام الإضافة
room
لتحديد دليل المخطط.
رائع
plugins {
id 'androidx.room'
}
room {
schemaDirectory "$projectDir/schemas"
}
Kotlin
plugins {
id("androidx.room")
}
room {
schemaDirectory("$projectDir/schemas")
}
إذا كان مخطّط قاعدة البيانات يختلف استنادًا إلى نوع الخيار أو النكهة أو الإصدار، يجب تحديد مواقع جغرافية مختلفة باستخدام schemaDirectory()
الإعداد عدة مرات، مع استخدام variantMatchName
كأول schemaDirectory()
مَعلمة. يمكن أن تتطابق كلّ إعدادات مع صيغة واحدة أو أكثر استنادًا إلى مقارنة بسيطة
مع اسم الصيغة.
تأكَّد من أنّ هذه المراجع شاملة وتغطي جميع الصيغ. يمكنك أيضًا تضمين
schemaDirectory()
بدون variantMatchName
للتعامل مع الصيغ التي لم تتم مطابقتها
بأي من الإعدادات الأخرى. على سبيل المثال، في تطبيق يتضمّن نوعَي ملفَي APK 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")
}
ضبط موقع المخطط باستخدام خيار معالج التعليقات التوضيحية
إذا كنت تستخدم الإصدار 2.5.2 أو إصدارًا أقدم من Room، أو إذا كنت لا تستخدم room.schemaLocation
مكوّن Gradle الإضافي لـ Room، اضبط موقع المخطّط باستخدام room.schemaLocation
خيار معالج التعليقات التوضيحية.
تُستخدَم الملفات في هذا الدليل كمدخلات ومخرجات لبعض مهام Gradle.
لضمان صحة عمليات الإنشاء المتزايدة والمخزّنة مؤقتًا وتحسين أدائها، عليك استخدام ملف CommandLineArgumentProvider
في Gradle
لإعلام Gradle بهذا الدليل.
أولاً، انسخ فئة RoomSchemaArgProvider
الموضَّحة أدناه إلىملف Gradle build الخاص بالوحدة. تُرسِل الطريقة 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()]
}
}
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
مع directory
المخطّط المحدّد:
رائع
// 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 من 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" }
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
يمكنها قراءة ملفات المخططات التي تم تصديرها. تنفِّذ الحزمة أيضًا واجهة
JUnit4
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}; }
التعامل بسلاسة مع مسارات نقل البيانات غير المتوفّرة
إذا لم تتمكّن مكتبة Room من العثور على مسار نقل بيانات لترقية قاعدة بيانات حالية على أحد
الأجهزة إلى الإصدار الحالي، يحدث خطأ
IllegalStateException
. إذا كان
من المقبول فقدان البيانات الحالية عند عدم توفّر مسار نقل البيانات، يمكنك استدعاء
طريقة
fallbackToDestructiveMigration()
builder عند إنشاء قاعدة البيانات:
Kotlin
Room.databaseBuilder(applicationContext, MyDb::class.java, "database-name") .fallbackToDestructiveMigration() .build()
Java
Room.databaseBuilder(getApplicationContext(), MyDb.class, "database-name") .fallbackToDestructiveMigration() .build();
تطلب هذه الطريقة من Room إعادة إنشاء الجداول في قاعدة بيانات تطبيقك بشكل مدمِّر عندما تحتاج إلى إجراء عملية نقل بيانات متزايدة ولا يتوفّر مسار نقل بيانات محدّد.
إذا كنت تريد أن يعود Room إلى إعادة الإنشاء التدميري في حالات معيّنة، هناك بعض البدائل لfallbackToDestructiveMigration()
:
- إذا كانت إصدارات معيّنة من سجلّ المخطّط تؤدي إلى ظهور أخطاء لا يمكنك حلّها
باستخدام مسارات نقل البيانات، استخدِم
fallbackToDestructiveMigrationFrom()
بدلاً من ذلك. تشير هذه الطريقة إلى أنّك تريد أن تعتمد Room على إعادة الإنشاء المهلكة فقط عند نقل البيانات من إصدارات معيّنة. - إذا كنت تريد أن يعود Room إلى إعادة الإنشاء التدميري فقط عند نقل بياناته
من إصدار أعلى من قاعدة البيانات إلى إصدار أقل، استخدِم
fallbackToDestructiveMigrationOnDowngrade()
بدلاً من ذلك.
التعامل مع القيم التلقائية للأعمدة عند الترقية إلى Room 2.2.0
في الإصدار 2.2.0 من Room والإصدارات الأحدث، يمكنك تحديد قيمة تلقائية لعمود باستخدام
التعليق التوضيحي
@ColumnInfo(defaultValue = "...")
.
في الإصدارات الأقدم من 2.2.0، كانت الطريقة الوحيدة لتحديد قيمة تلقائية عمود
هي تحديدها مباشرةً في عبارة SQL تم تنفيذها، ما يؤدي إلى إنشاء قيمة
تلقائية لا تعرفها Room. وهذا يعني أنّه إذا تم إنشاء قاعدة بيانات
أصلاً باستخدام إصدار من Room أقدم من 2.2.0، قد يتطلّب ترقية تطبيقك ليعمل باستخدام Room 2.2.0 توفير مسار نقل بيانات خاص
بالقيم التلقائية الحالية التي حدّدتها بدون استخدام واجهات برمجة تطبيقات Room.
على سبيل المثال، لنفترض أنّ الإصدار 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، فإنّ أي مستخدمين ثبَّتوا التطبيق بدءًا من الإصدار 2 لن تتوفر لديهم القيمة التلقائية لعمود tag
في مخطّط قاعدة البيانات.
في الإصدارات الأقدم من Room 2.2.0، لا يشكّل هذا الاختلاف أي ضرر. ومع ذلك، إذا
تم ترقية التطبيق لاحقًا لاستخدام Room 2.2.0 أو إصدار أحدث وغيّر فئة
عنصر Song
لتضمين قيمة تلقائية لـ tag
باستخدام التعليق التوضيحي
@ColumnInfo
، يمكن أن يرصد Room
هذا التناقض. ويؤدي ذلك إلى تعذُّر إتمام عمليات التحقّق من صحة المخطط.
للمساعدة في ضمان اتساق مخطّط قاعدة البيانات لجميع المستخدمين عند تحديد قيم عمود التلقائية في مسارات نقل البيانات السابقة، عليك إجراء ما يلي في المرة الأولى التي تُجري فيها ترقية لتطبيقك لاستخدام Room 2.2.0 أو إصدار أحدث:
- يمكنك تحديد القيم التلقائية للأعمدة في فئات العناصر ذات الصلة باستخدام التعليق التوضيحي
@ColumnInfo
. - ارفع رقم إصدار قاعدة البيانات بمقدار 1.
- حدِّد مسار نقل البيانات إلى الإصدار الجديد الذي ينفِّذ استراتيجية الحذف وإعادة الإنشاء لإضافة القيم التلقائية اللازمة إلى الأعمدة الحالية.
يوضّح المثال التالي هذه العملية:
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"); } };