Jangan berasumsi, saya memiliki database Room sederhana:
@Database(entities = {User.class}, version = 1)
abstract class AppDatabase extends RoomDatabase {
public abstract Dao getDao();
}
Sekarang, saya menambahkan entitas baru: Pet
dan mengganti versi ke 2:
@Database(entities = {User.class, Pet.class}, version = 2)
abstract class AppDatabase extends RoomDatabase {
public abstract Dao getDao();
}
Tentu saja, Room memberikan pengecualian: java.lang.IllegalStateException: A migration from 1 to 2 is necessary.
Dengan asumsi, saya belum mengubah User
kelas (jadi semua data aman), saya harus menyediakan migrasi yang hanya membuat tabel baru. Jadi, saya mencari kelas yang dihasilkan oleh Room, mencari kueri yang dihasilkan untuk membuat tabel baru saya, menyalinnya dan menempelkannya ke migrasi:
final Migration MIGRATION_1_2 =
new Migration(1, 2) {
@Override
public void migrate(@NonNull final SupportSQLiteDatabase database) {
database.execSQL("CREATE TABLE IF NOT EXISTS `Pet` (`name` TEXT NOT NULL, PRIMARY KEY(`name`))");
}
};
Namun saya merasa tidak nyaman untuk melakukannya secara manual. Adakah cara untuk memberi tahu Room: Saya tidak menyentuh salah satu tabel yang ada, jadi data aman. Tolong buat migrasi untuk saya?
java
android
database-migration
android-room
Piotr Aleksander Chmielowski
sumber
sumber
Jawaban:
Ruangan yang tidak memiliki baik Migrasi Sistem, setidaknya tidak sampai
2.1.0-alpha03
.Jadi, hingga kami memiliki Sistem Migrasi yang lebih baik, ada beberapa solusi untuk memudahkan Migrasi di dalam Ruangan.
Karena tidak ada metode seperti
@Database(createNewTables = true)
atauMigrationSystem.createTable(User::class)
, yang seharusnya ada satu atau lainnya, satu-satunya cara yang mungkin adalah berjalanCREATE TABLE IF NOT EXISTS `User` (`id` INTEGER, PRIMARY KEY(`id`))
di dalam
migrate
metode Anda .val MIGRATION_1_2 = object : Migration(1, 2){ override fun migrate(database: SupportSQLiteDatabase) { database.execSQL("CREATE TABLE IF NOT EXISTS `User` (`id` INTEGER, PRIMARY KEY(`id`))") } }
Untuk mendapatkan skrip SQL di atas , Anda memiliki 4 cara
1. Tulis sendiri
Pada dasarnya, Anda harus menulis skrip di atas yang akan cocok dengan skrip yang dihasilkan Room. Cara ini mungkin, tidak mungkin. (Pertimbangkan Anda memiliki 50 bidang)
2. Skema Ekspor
Jika Anda menyertakan
exportSchema = true
di dalam@Database
anotasi Anda , Room akan menghasilkan skema database dalam / skema folder proyek Anda. Penggunaannya@Database(entities = [User::class], version = 2, exportSchema = true) abstract class AppDatabase : RoomDatabase { //... }
Pastikan Anda telah menyertakan baris di bawah ini dalam
build.grade
modul aplikasi Andakapt { arguments { arg("room.schemaLocation", "$projectDir/schemas".toString()) } }
Saat Anda menjalankan atau membangun proyek, Anda akan mendapatkan file JSON
2.json
, yang memiliki semua kueri dalam database Room Anda."formatVersion": 1, "database": { "version": 2, "identityHash": "325bd539353db508c5248423a1c88c03", "entities": [ { "tableName": "User", "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, PRIMARY KEY(`id`))", "fields": [ { "fieldPath": "id", "columnName": "id", "affinity": "INTEGER", "notNull": true },
Jadi, Anda dapat memasukkan di atas
createSql
dalammigrate
metode Anda .3. Dapatkan kueri dari AppDatabase_Impl
Jika Anda tidak ingin mengekspor skema, Anda masih bisa mendapatkan kueri dengan menjalankan atau membangun proyek yang akan menghasilkan
AppDatabase_Impl.java
file. dan dalam file tertentu yang dapat Anda miliki.@Override public void createAllTables(SupportSQLiteDatabase _db) { _db.execSQL("CREATE TABLE IF NOT EXISTS `User` (`id` INTEGER, PRIMARY KEY(`id`))");
Dalam
createAllTables
metode ini, akan ada skrip buat semua entitas. Anda bisa mendapatkannya dan memasukkannya ke dalammigrate
metode Anda .4. Pemrosesan Anotasi.
Seperti yang Anda duga, Room menghasilkan semua yang disebutkan di atas
schema
, danAppDatabase_Impl
file dalam waktu kompilasi dan dengan Pemrosesan Anotasi yang Anda tambahkankapt "androidx.room:room-compiler:$room_version"
Itu berarti Anda juga dapat melakukan hal yang sama dan membuat pustaka pemrosesan anotasi Anda sendiri yang menghasilkan semua kueri pembuatan yang diperlukan untuk Anda.
Idenya adalah membuat pustaka pemrosesan anotasi untuk anotasi Room
@Entity
dan@Database
. Ambil kelas yang diberi catatan@Entity
misalnya. Ini adalah langkah-langkah yang harus Anda ikutiStringBuilder
dan tambahkan "BUAT TABEL JIKA TIDAK ADA"class.simplename
atau menuruttableName
bidang@Entity
. Tambahkan keStringBuilder
@ColumnInfo
anotasi. Untuk setiap bidang, Anda harus menambahkanid INTEGER NOT NULL
gaya kolom ke AndaStringBuilder
.@PrimaryKey
ForeignKey
danIndices
jika ada.public final class UserSqlUtils { public String createTable = "CREATE TABLE IF NOT EXISTS User (id INTEGER, PRIMARY KEY(id))"; }
Kemudian, Anda dapat menggunakannya sebagai file
val MIGRATION_1_2 = object : Migration(1, 2){ override fun migrate(database: SupportSQLiteDatabase) { database.execSQL(UserSqlUtils().createTable) } }
Saya membuat perpustakaan seperti itu untuk diri saya sendiri yang dapat Anda periksa, dan bahkan menggunakannya dalam proyek Anda. Perhatikan bahwa perpustakaan yang saya buat tidak penuh dan hanya memenuhi persyaratan saya untuk pembuatan tabel.
RoomExtension untuk Migrasi yang lebih baik
Aplikasi yang menggunakan RoomExtension
Semoga bermanfaat.
MEMPERBARUI
Pada saat menulis jawaban ini, versi kamar adalah
2.1.0-alpha03
dan ketika saya mengirim email kepada pengembang, saya mendapat tanggapanSayangnya, kami masih kekurangan Sistem Migrasi yang lebih baik.
sumber
Maaf, Room tidak mendukung pembuatan tabel secara otomatis tanpa kehilangan data.
Migrasi wajib ditulis. Jika tidak, ini akan menghapus semua data dan membuat struktur tabel baru.
sumber
Anda bisa melakukan ini-
@Database(entities = {User.class, Pet.class}, version = 2) abstract class AppDatabase extends RoomDatabase { public abstract Dao getDao(); public abstract Dao getPetDao(); }
Sisa akan sama seperti yang Anda sebutkan di atas-
db = Room.databaseBuilder(this, AppDatabase::class.java, "your_db") .addMigrations(MIGRATION_1_2).build()
Referensi - Untuk lebih lanjut
sumber
Anda dapat menambahkan perintah gradle berikut ke defaultConfig Anda di app.gradle:
javaCompileOptions { annotationProcessorOptions { arguments = ["room.schemaLocation": "$projectDir/schemas".toString()] } }
Ketika Anda menjalankan ini, itu akan menyusun daftar nama tabel dengan pernyataan CREATE TABLE yang relevan dari mana Anda bisa menyalin dan menempelkannya ke objek migrasi Anda. Anda mungkin harus mengubah nama tabel.
Misalnya ini dari skema yang saya buat:
"tableName": "assets", "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`asset_id` INTEGER NOT NULL, `type` INTEGER NOT NULL, `base` TEXT NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`asset_id`))"
Jadi saya menyalin dan menempelkan pernyataan createSql dan mengubah '$ {TABLE_NAME}' menjadi 'aset' nama tabel, dan pernyataan Room membuat dibuat secara otomatis.
sumber
Dalam kasus ini, Anda tidak perlu melakukan migrasi, Anda dapat memanggil .fallbackToDestructiveMigration () saat Anda membuat instance database.
Contoh:
instance = Room.databaseBuilder(context, AppDatabase.class, "database name").fallbackToDestructiveMigration().build();
Dan jangan lupa untuk mengubah versi database.
sumber
Mungkin dalam kasus ini (jika Anda hanya membuat tabel baru tanpa mengubah yang lain) Anda dapat melakukan ini tanpa membuat migrasi sama sekali?
sumber