Ich entwickle eine Android-App mit "Room", einer von Google erstellten Persistenzbibliothek. Da es sich um eine relativ neue Bibliothek handelt, ist die Migrationsfunktion nicht cool. .. .. Was ich tun wollte, war "eine REAL-Typspalte in einen INTEGER-Typ ändern", aber die SQLite-Spezifikation, dass "nur das Hinzufügen von Spalten mit der ALTER-Anweisung möglich ist" und eine exquisite Ehe wurden erstellt und realisiert. Es fiel mir schwer, es zu tun ... Dieser Artikel ist dieses Memo.
Ich werde zuerst aus dem Lösungsverfahren schreiben.
Version
von @ Database
Ich glaube nicht, dass Sie es bei dieser Geschwindigkeit sehr gut verstehen können, also schauen wir uns jedes Detail an.
Zum Beispiel, wenn Sie die folgende Entität "Produkt" haben
Product.kt
@Entity(indices = [Index(value = ["name"])])
data class Product(
@PrimaryKey(autoGenerate = true) var id: Int = 0,
var name: String? = null,
var price: Double? = null,
...
Ändern Sie das "Double" dieses "Preises" in "Int" und so weiter. Nun, das ist natürlich.
Die Änderung von 1. sollte (normalerweise) einen Build-Fehler verursachen, also zerstören Sie ihn nacheinander. Wie das Problem behoben werden kann, hängt von der Implementierung ab. Daher werde ich es hier weglassen.
Vielleicht definieren Sie eine sub-abstrakte Klasse für "RoomDatabase" wie folgt:
AppDatabase.kt
@Database(entities = [Product::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
companion object {
@Volatile private var instance: AppDatabase? = null
fun getInstance(context: Context): AppDatabase {
return instance ?: synchronized(this) {
instance ?: buildDatabase(context).also { instance = it }
}
}
private fun buildDatabase(context: Context): AppDatabase {
return Room.databaseBuilder(context.applicationContext, AppDatabase::class.java, "hogehoge-database")
.build()
}
}
}
Erhöhen Sie die Version
hier um eins. In diesem Beispiel ist es auf 2 gesetzt. Das bedeutet, dass die Schemaversion der Datenbank auf 2 gesetzt wird.
Dies war der nervigste Geruch. Raum tut fast nichts gegen Migration. Daher müssen Sie unformatiertes SQL schreiben. Da die Angabe von SQLite lautet "Spalten können nicht geändert oder gelöscht werden", besteht die Methode darin, eine neue Tabelle zu definieren, die aktuellen Daten in diese zu übertragen, die alte Tabelle zu löschen und die neue Tabelle dann in ihren ursprünglichen Namen umzubenennen. Ich werde das machen. Schließlich ist dies eine Gefahr, aber der Index, der beim Löschen für die alte Tabelle festgelegt wurde, wird ebenfalls gelöscht. Sie müssen dies also nach dem Erstellen der neuen Tabelle erstellen.
Zunächst die Anweisung CREATE TABLE, aber ich denke, es ist sehr mühsam, von Grund auf neu zu schreiben. Verwenden wir also die Raumschemaausgabe json. Wenn die folgende Beschreibung in app / build.gradle
enthalten ist, werden die Schemainformationen json beim Erstellen ausgespuckt.
app/build.gradle
android {
...
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
}
}
Wenn Sie damit erstellen, werden die Schemainformationen unter app / schemas
als json ausgegeben. Der Dateiname lautet * Schemaversion * .json.
Wenn ich mir diesen JSON anschaue, denke ich, dass die Anweisung CREATE TABLE im Schlüssel createSql
definiert ist. Es ist einfach, es zu kopieren und die erforderlichen Änderungen vorzunehmen.
Der tatsächliche Migrationscode lautet also wie folgt. Nehmen Sie das vorherige Beispiel von "AppDatabase.kt"
AppDatabase.kt
...
private fun buildDatabase(context: Context): AppDatabase {
val migration1to2 = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE TABLE IF NOT EXISTS `Geeigneter Tabellenname` ...")
}
}
return Room.databaseBuilder(context.applicationContext, AppDatabase::class.java, "onieasy-database")
.addMigrations(migration1to2)
.build()
}
...
Ersetzen Sie die Schemaversion durch die tatsächliche.
Es wird später umbenannt, sodass Sie den "entsprechenden Tabellennamen" verwenden können. Neben TABELLE ERSTELLEN
nicht wahr.
val migration1to2 = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("TABELLE ERSTELLEN, WENN NICHT EXISTIERT Geeigneter Tabellenname...")
database.execSQL("INSERT INTO Geeigneter Tabellenname SELECT*FROM Tabellenname, den Sie ändern möchten")
database.execSQL("DROP TABLE Der Name der Tabelle, die Sie ändern möchten")
database.execSQL("ALTER TABLE Geeigneter Tabellenname RENAME TO Tabellenname, den Sie ändern möchten")
}
}
Wenn es ursprünglich indiziert wurde, kopieren Sie es schließlich aus dem Schema json. Es sollte "createSql" in "Indizes" geben.
database.execSQL("CREATE INDEX index_Product_name` ON `Product` (`name`)")
Es ist wie es ist.
Lassen Sie uns alles auf einmal tun, es erstellen und die App ausführen. Wenn Sie es richtig ändern können, sollte es normal funktionieren.
Der Raum entwickelt sich noch, daher denke ich, dass es eine Menge zu tun gibt. Die erste Idee, die ich hatte, war, eine neue Entität in Kotlin zu definieren und die Daten an diese neue Entität zu übertragen. Ich habe es versucht, aber das Ergebnis ist, dass die App nicht gestartet wird ... Wie, ** Room erstellt eine Tabelle aus einer Entität nur im Fall von Schema Version 1 (dh beim ersten Mal), aber danach wird die Tabelle generiert. Es wird nicht automatisch generiert! ** Was zur Hölle ...
Deshalb ist es bei der Verwendung von Room problematisch, wenn Sie den Tisch nicht von Anfang an genau entwerfen, ja, das habe ich gelernt.
Recommended Posts