Je développe une application Android à l'aide de "Room", qui est une bibliothèque de persistance créée par Google. Parce que c'est une bibliothèque relativement nouvelle, la fonction de migration n'est pas cool. .. .. Ce que je voulais faire était de "changer une colonne de type REAL en un type INTEGER", mais la spécification de sqlite selon laquelle "seulement l'ajout de colonnes peut être fait avec l'instruction ALTER" et un mariage exquis ont été créés et réalisés. J'ai eu du mal à le faire ... Cet article est ce mémo.
J'écrirai d'abord la procédure de solution.
version
de @ Database
Je ne pense pas que vous puissiez très bien le comprendre à ce rythme, alors jetons un coup d'œil à chaque détail.
Par exemple, si vous avez l'entité Product
suivante
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,
...
Changez le Double?
De ce prix
en ʻInt?`, Et ainsi de suite.
Eh bien, c'est naturel.
Le changement dans 1. devrait (généralement) provoquer une erreur de construction, donc écrasez-le un par un. La façon de le résoudre dépend de l'implémentation, je vais donc l'omettre ici.
version
de @ Database
Peut-être que vous définissez une classe sous-abstraite pour RoomDatabase
comme ceci:
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()
}
}
}
Augmentez la version
ici de un. Dans cet exemple, il est défini sur 2. Cela signifie définir la version de schéma de la base de données sur 2.
C'était l'odeur la plus ennuyeuse. Room ne fait presque rien sur la migration. En conséquence, vous devez écrire du SQL brut. Puisque la spécification sqlite dit que "les colonnes ne peuvent pas être modifiées ou supprimées", la méthode consiste à définir une nouvelle table, à y transférer les données actuelles, à supprimer l'ancienne table, puis à renommer la nouvelle table à son nom d'origine. Je le ferai. Enfin, c'est un piège, mais l'index qui a été défini sur l'ancienne table lors de sa suppression est également supprimé, vous devez donc le créer après avoir créé la nouvelle table.
Tout d'abord, l'instruction CREATE TABLE, mais je pense qu'il est très gênant d'écrire à partir de zéro, alors utilisons la sortie de schéma de salle json. S'il y a la description suivante dans ʻapp / build.gradle`, les informations de schéma json seront crachées au moment de la construction.
app/build.gradle
android {
...
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
}
}
Lorsque vous construisez avec ceci, les informations de schéma sont affichées sous forme de json sous ʻapp / schemas`. Le nom du fichier est * version du schéma * .json.
En regardant ce json, je pense que l'instruction CREATE TABLE est définie dans la clé createSql
. Il est facile de le copier et d'apporter les modifications nécessaires.
Ainsi, le code de migration réel est le suivant. Prenant l'exemple de ʻAppDatabase.kt` plus tôt
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 `Nom de table approprié` ...")
}
}
return Room.databaseBuilder(context.applicationContext, AppDatabase::class.java, "onieasy-database")
.addMigrations(migration1to2)
.build()
}
...
Remplacez la version du schéma par la version actuelle.
Il sera renommé plus tard, vous pourrez donc utiliser le «nom de table approprié». À côté de CREATE TABLE
n'est-ce pas.
val migration1to2 = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE TABLE IF NOT EXISTS Nom de table approprié...")
database.execSQL("INSERT INTO Nom de table approprié SELECT*FROM Nom de la table que vous souhaitez modifier")
database.execSQL("DROP TABLE Le nom de la table que vous souhaitez modifier")
database.execSQL("ALTER TABLE Nom de table approprié RENAME TO Nom de table que vous souhaitez modifier")
}
}
Enfin, s'il a été indexé à l'origine, copiez-le depuis le schéma json. Il devrait y avoir createSql
dans ʻindices`.
database.execSQL("CREATE INDEX index_Product_name` ON `Product` (`name`)")
C'est comme ça.
Faisons tout cela en même temps, construisons-le et exécutons l'application. Si vous pouvez le modifier correctement, cela devrait fonctionner normalement.
La salle se développe encore, donc je pense qu'il y a pas mal de choses à faire. La première idée que j'ai eue était de définir une nouvelle entité dans Kotlin et de transférer les données vers cette nouvelle entité. Je l'ai essayé, mais le résultat est que l'application ne démarre pas ... Comment, ** Room crée une table à partir d'une entité uniquement dans le cas de la version de schéma 1 (c'est-à-dire la première fois), mais après cela, la table est générée. Il ne se génère pas automatiquement! ** Que se passe-t-il ...
C'est pourquoi lorsque vous utilisez Room, si vous ne concevez pas la table exactement depuis le début, ce sera gênant, oui, j'ai appris.
Recommended Posts