سلام شاید شما هم یه برنامه قدیمی دارید که تو یه مارکت منتشر کردید و از ابزار های قدیمی توی برنامه تون استفاده کردین، مثلا با جاوا کد زدین از volley استفاده کردین یا کلی چیز دیگه که بعضی از اینا رو میشه به راحتی تغییر داد .مثلا کد جدید که ریفکتور کردین رو با retrofit بزنین. اما تو بعضی موارد نیازه یه کارایی بکنین تا از ابزار جدید بشه استفاده کرد. یکی از همین موارد اینه که بخواین از دیتابیس sqlite به room مهاجرت کنین . تو این مورد باید حواستون باشه اطلاعات قدیمی کاربر بعد به روز رسانی حذف نشن یه وقت و یه عالمه فیدبک منفی نگیرین . مستقیما بریم سمت راه حل و اینکه جیکار باید بکنیم.
//model
@Entity(tableName = "your_table") data class YourEntity( @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "id") var id: Int, @ColumnInfo(name = "name") var name:String , @ColumnInfo(name = "phone") var phone:String? )
//DAO
@Dao interface YourDao { @Query("SELECT * FROM your_table") fun getAll(): List<YourEntity> }
نکته: برای نوشتن کد مهاجرت (Migration) از SQLite به Room، باید مطمئن شید که ساختار جدول و نام ستونها تو هر دو نسخه یکسان هستند. با توجه به اسکیمای دیتابیس قدیمی و اینتیتی جدید، میتونید کد مهاجرت رو به صورت زیر بنویسید:
اگر از hilt به عنوان dependency injection استفاده می کنید کلاس AppDatabase خودتون را به شکل زیر provide کنید:
@Singleton @Provides fun provideDb(@ApplicationContext context: Context, ): AppDatabase { return Room.databaseBuilder(context, AppDatabase::class.java, AppDatabase.DATABASE_NAME) .allowMainThreadQueries() .fallbackToDestructiveMigration() .addMigrations(AppDatabase.MIGRATION_1_2) .build() }
و کلاس AppDataBase رو به شکل زیر بسازید:
@Database( entities = [ YourEntity::class ], version = 2 ) abstract class AppDatabase : RoomDatabase() { abstract fun yourDao(): YourDao companion object { //حواستون باشه اسم دیتابیس همون چیزی باشه که تو ورژن قبلی بود val DATABASE_NAME: String = "نام دیتابیس" val MIGRATION_1_2 = object : Migration(1, 2) { override fun migrate(database: SupportSQLiteDatabase) { //پیاده سازی در ادامه توضیح داده خواهد شد } }
اما اگه از hilt استفاده نمی کنید کلاس AppDatabsae شما به این شکل میشه:
@Database(entities = [YourEntity::class], version = 2) abstract class AppDatabase : RoomDatabase() { abstract fun yourDao(): YourDao companion object { @Volatile private var INSTANCE: AppDatabase? = null fun getDatabase(context: Context): AppDatabase { return INSTANCE ?: synchronized(this) { val instance = Room.databaseBuilder( context.applicationContext, AppDatabase::class.java, //حواستون باشه اسم دیتابیس همون چیزی باشه که تو ورژن قبلی بود "نام دیتابیس" ).addMigrations(MIGRATION_1_2).build() INSTANCE = instance instance } } val MIGRATION_1_2 = object : Migration(1, 2) { override fun migrate(database: SupportSQLiteDatabase) { //پیاده سازی در ادامه } }
نکته اول: آبجکتی که از نوع Migration ساختیم دوتا int توی کانسترکتور خودش می گیره که اولی نسخه قبلی دیتابیستونه و دومی نسخییه که الان داریم اگه این دوتا درست نباشن مهاجرت اتفاق نمیفته.
نکته دوم:کلمه کلیدی @Volatile
برای تضمین این استفاده میشه که متغیر INSTANCE
همیشه بهروزترین مقدار خودش رو برای تمام نخها (threads) به اشتراک بگذاره. با این کار، از شرایط رقابتی (race conditions) جلوگیری میشه که ممکنه باعث شه چندین نمونه از کلاس AppDatabase
ایجاد شه.
تو این مرحله که تقریبا مرحله آخرمونه توی فانکشن migrate که override کردیم کوئری هی خودمون رو می نویسیم مثل این مثال :
override fun migrate(database: SupportSQLiteDatabase) { // Create the new table database.execSQL("""CREATE TABLE IF NOT EXISTS `your_new_table` ( `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `phone` TEXT ) """.trimIndent()) // Copy the data database.execSQL(""" INSERT INTO `your_new_table` (`id`, `name`, `phone`) SELECT `id`, `name`, `phone` FROM `your_table` """.trimIndent()) // Remove the old table database.execSQL("DROP TABLE `your_table`") // Rename the new table to the old table name database.execSQL("ALTER TABLE `your_new_table` RENAME TO `your_table`") }
خب کاری که کردیم اینه :
تمام شد به همین راحتی فقط یه مورد دیگه اضافه کنم
اگر table جدیدی به دیتابیستون اضافه شده تو متد migrate باید بسازیدش (فقط CREATE TABLE IF NOT EXISTS)
امیدوارم این مطلب براتون مفید باشه و لذت برده باشید.
تا دیداری دیگر بدرود...