Java.lang.IllegalStateException
La migration n'a pas correctement géré l'utilisateur (therealandroid.github.com.roomcore.Java.User).
Attendu:
TableInfo {name = 'user', columns = {name = Column {name = 'name', type = 'TEXT', notNull = false, primaryKeyPosition = 0}, age = Column {name = 'age', type = 'INTEGER ', notNull = true, primaryKeyPosition = 0}, id = Column {name =' id ', type =' INTEGER ', notNull = true, primaryKeyPosition = 1}}, foreignKeys = []} Trouvé:
A trouvé
TableInfo {name = 'user', columns = {name = Column {name = 'name', type = 'TEXT', notNull = false, primaryKeyPosition = 0}, id = Column {name = 'id', type = 'INTEGER ', notNull = true, primaryKeyPosition = 1}, age = Column {name =' age ', type =' INTEGER ', notNull = false, primaryKeyPosition = 0}}, foreignKeys = []}
J'essaie d'effectuer une migration simple, j'ai une classe appelée User
et elle a deux colonnes ID (primary key)
et NAME TEXT
puis je remplis la base de données avec deux données utilisateurs, puis j'ajoute la colonne AGE
dans l'objet User
et dans la constante de migration j'ajoute un alter table
pour ajouter cette nouvelle colonne et enfin je remplace la version de la base de données 1 à 2.
Voici le code
User.class
@Entity(tableName = "user")
public class User {
@PrimaryKey
private int id;
@ColumnInfo(name = "name")
private String name;
@ColumnInfo(name = "age")
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Classe de base de données
@Database(entities = {User.class}, version = 2)
public abstract class RoomDatabaseImpl extends RoomDatabase {
abstract UserDao userDao();
}
Code de migration
public static Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'age' INTEGER");
}
};
et ça appelle
Room.databaseBuilder(context, RoomDatabaseImpl.class, "Sample.db")
.addMigrations(MIGRATION_1_2)
.allowMainThreadQueries()
.build();
Avant de changer l'objet en ajoutant AGE
et en effectuant la migration j'ajoute deux registres et ça marche.
Après avoir effectué la migration, j'ai juste essayé d'ajouter un nouvel utilisateur comme ci-dessous:
User user = new User();
user.setName("JoooJ");
user.setId(3);
user.setAge(18);
List<User> userList = new ArrayList<>();
userList.add(user);
App.database(this).userDao().insertAll(userList); // The crash happens here
Autres renseignements:
Android Studio 3 et je n'ai pas testé dans la réalité.
Dépendances:
compile "Android.Arch.persistence.room:runtime:1.0.0-alpha9-1"
annotationProcessor "Android.Arch.persistence.room:compiler:1.0.0-alpha9-1"
compile "Android.Arch.persistence.room:rxjava2:1.0.0-alpha9-1"
gradle 2.3.3
Quelqu'un peut-il m'aider s'il vous plaît, je ne sais vraiment pas ce que je fais mal ou si c'est un bug.
Le message d'erreur est difficile à analyser, mais il y a une différence:
TableInfo {name = 'user', columns = {name = Column {name = 'name', type = 'TEXT', notNull = false, primaryKeyPosition = 0}, age = Column {name = 'age', type = 'INTEGER ', notNull = true, primaryKeyPosition = 0}, id = Column {name =' id ', type = 'INTEGER', notNull = true, primaryKeyPosition = 1}}, foreignKeys ]} Trouvé:
A trouvé
TableInfo {name = 'user', columns = {name = Column {name = 'name', type = 'TEXT', notNull = false, primaryKeyPosition = 0}, id = Column {name = 'id', type = 'INTEGER ', notNull = true, primaryKeyPosition = 1}, age = Column {name =' age ', type =' INTEGER ', == [- notNull = false, primaryKeyPosition = 0}}, foreignKeys = []}
L'âge est nul, mais Room s'attendait à ce qu'il ne soit pas nul.
Modifiez votre migration en:
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'age' INTEGER NOT NULL");
Puisque cette explication d'exception est TRÈS difficile à analyser, j'ai créé n petit script qui fait la différence pour vous.
Exemple:
mig "Java.lang.IllegalStateException: Migration failed. expected:TableInfo{name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, age=Column{name='age', type='INTEGER', notNull=true, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}}, foreignKeys=[]} , found:TableInfo{name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}, age=Column{name='age', type='INTEGER', notNull=false, primaryKeyPosition=0}}, foreignKeys=[]}"
Résultat:
J'ai aussi écrit un petit script JS que vous pouvez trouver https://hrankit.github.io/RoomSQLiteDifferenceFinder/
Le processus est assez simple.
Entrez le journal des erreurs attendues dans la colonne attendue qui est celle de gauche.
Entrez le journal des erreurs trouvées dans la colonne Trouvé qui est la bonne.
Appuyez sur Go. bouton. Les journaux d'erreurs sont convertis en JSON.
Appuyez sur le bouton Comparer et Voila, vous avez la différence dont vous avez besoin.
Ce plugin découvre la différence entre les deux vidages attendus et trouvés du Android Studio Logcat.
Découvrez l'image de comparaison ici
Aucune des réponses n'est correcte dans aucun des liens. Après de nombreuses expériences, a trouvé un moyen pour cela. La requête ALTER doit être écrite de la manière suivante pour la faire fonctionner:
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'age' INTEGER NOT NULL DEFAULT 0")
Cependant, la valeur par défaut entière peut être n'importe quoi.
Si vous souhaitez ajouter une colonne de type String, ajoutez de la manière suivante:
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'address' TEXT")
Cela fonctionne comme un charme.
J'ai rencontré ce problème aujourd'hui, je viens de changer les champs int
en Integer
dans Entities
. Comme int
ne peut pas être null mais que les objets Integer
peuvent être null.
Si vous obtenez des différences notNull, vous pouvez simplement marquer votre champ de classe avec l'annotation @NonNull, ou changer votre sql avec ALTER TABLE. Mais si vous obtenez des différences de type de colonne, comme prévu: TYPE = TEXT, puis trouvé TYPE = '' (COLLATE NOCASE), ou INTEGER attendu, trouvé INT, alors la seule solution est de supprimer et de recréer votre table. Sqlite ne permet pas de modifier les types de colonnes.
Utilisez INTEGER dans Sqlite au lieu de INT et marquez votre Java avec @ColumnInfo (collate = NOCASE) (si vous utilisez NOCASE dans Sqlite).
Jetez un œil au fichier json sous app\schemas pour obtenir le sql pour les requêtes attendues.
static final Migration MIGRATION_2_3= new Migration(2, 3) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("DROP TABLE IF EXISTS table_tmp");
database.execSQL("CREATE TABLE IF NOT EXISTS `table_tmp` ...");
database.execSQL("insert into table_tmp (`id`, `name` , ...");
database.execSQL("DROP INDEX IF EXISTS `index_table_name`");
database.execSQL("CREATE INDEX IF NOT EXISTS `index_table_name` ON `table_tmp` (`name`)");
database.execSQL("DROP TABLE IF EXISTS table");
database.execSQL("alter table table_tmp rename to table");
}
};