Je suis en train de développer une application qui utilise la bibliothèque ORMLite (ce qui est formidable), mais je suis un débutant.
J'ai une question sur la mise à jour de la base de données à l'intérieur de l'appareil.
Disons que quelqu'un télécharge mon application sur Google Play. Quelques mois plus tard, je vais certainement renseigner certaines tables avec de nouvelles entrées.
Lorsque cette personne effectue une mise à jour de l'application, comment puis-je simplement mettre à jour la base de données avec mes nouvelles entrées et conserver les anciennes à l'intérieur.
Pour être plus clair, imaginons que l'utilisateur réponde aux questions de mon application. Quand je vais introduire de nouvelles questions, comment puis-je les insérer dans la base de données lorsqu'il met à jour mon application et conserve les questions auxquelles il a déjà été répondu?
Lorsque cette personne effectue une mise à jour de l'application, comment puis-je simplement mettre à jour la base de données avec mes nouvelles entrées et conserver les anciennes à l'intérieur.
L'idée est d'utiliser le numéro de version transmis à la méthode onUpgrade(...)
. Avec ORMLite , la méthode OrmLiteSqliteOpenHelper.onUpgrade(...)
prend un nombre oldVersion
et newVersion
. Vous pouvez ensuite écrire dans votre application un code de conversion capable de convertir les données de l'ancien format et de mettre à jour le schéma.
Pour plus d'informations, voir la documentation ORMLite sur le sujet:
Pour citer, vous pouvez faire quelque chose comme ceci:
if (oldVersion < 2) {
// we added the age column in version 2
dao.executeRaw("ALTER TABLE `account` ADD COLUMN age INTEGER;");
}
if (oldVersion < 3) {
// we added the weight column in version 3
dao.executeRaw("ALTER TABLE `account` ADD COLUMN weight INTEGER;");
}
Si vous avez des données existantes que vous devez convertir, vous devez effectuer les conversions en SQL si possible.
Une autre alternative serait d'avoir une entité Account
et une entité OldAccount
qui pointent vers le même nom de table. Vous pouvez ensuite lire les entités OldAccount
à l'aide de oldAccountDao
, les convertir en entités Account
, puis les mettre à jour à l'aide de accountDao
dans la même table. Vous devez faire attention ici aux caches d'objets.
Je le fais de cette façon:
@Override
public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
switch (oldVersion) {
case 1:
updateFromVersion1(database, connectionSource, oldVersion, newVersion);
break;
case 2:
updateFromVersion2(database, connectionSource, oldVersion, newVersion);
break;
default:
// no updates needed
break;
}
}
private void updateFromVersion1(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
// do some stuff here
onUpgrade(database, connectionSource, oldVersion + 1, newVersion);
}
private void updateFromVersion2(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
// do some stuff here
onUpgrade(database, connectionSource, oldVersion + 1, newVersion);
}
Cela mettra à jour de manière incrémentielle la base de données des utilisateurs indépendamment de la version de la base de données à laquelle il vient.
Peu d'informations, il n'est pas clair si les modifications que vous avez la structure de la table.
a) Si vous ne modifiez pas la structure de la base de données.
1 Dans la nouvelle version de votre programme lorsque vous commencez à vérifier une version précédemment enregistrée (par exemple, dans les préférences) avec la version actuelle (voir PackageManager.getPackageInfo).
saved = 0 - L'utilisateur vient d'installer la nouvelle version
saved <current - L'utilisateur met à jour votre programme
2 Ajouter de nouvelles données à la base
3 Enregistrer la version actuelle dans les préférences
b) Si la structure de la table a été modifiée (ajout ou suppression de champs)
1 Augmentez le numéro de version de votre base de données (reportez-vous à la classe expand OrmLiteSqliteOpenHelper).
2 Lorsque l'utilisateur se connecte pour la première fois à votre programme, la méthode 'onUpgrade' sera appelée (dans votre classe étendue OrmLiteSqliteOpenHelper) qui sera transférée vers les anciens et les nouveaux numéros de version.
Je n'aime pas perdre la base de données à chaque mise à jour, ou écrire un code de mise à jour après avoir ajouté chaque champ, alors ...
J'essaie de le faire comme ça:
@Override
public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
ArrayList<String> tableNames = getTableNames(database);
for (Class clazz : daoClasses) {
try {
Annotation annotation = clazz.getAnnotation(DatabaseTable.class);
if (annotation != null && annotation instanceof DatabaseTable) {
String tableName = ((DatabaseTable) annotation).tableName();
if (tableName.isEmpty()) {
tableName = clazz.getSimpleName().substring(0, 1).toLowerCase() + clazz.getSimpleName().substring(1);
}
if(!tableNames.contains(tableName)){
TableUtils.createTable(connectionSource, clazz);
} else {
addColumns(database, tableName, clazz);
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
private ArrayList<String> getTableNames(SQLiteDatabase database){
ArrayList<String> tableNames = new ArrayList<>();
Cursor cursor = database.rawQuery("SELECT name FROM sqlite_master WHERE type='table'", null);
if (cursor.moveToFirst()) {
while ( !cursor.isAfterLast() ) {
tableNames.add(cursor.getString(0));
cursor.moveToNext();
}
}
cursor.close();
return tableNames;
}
private void addColumns(SQLiteDatabase database, String tableName, Class clazz){
Cursor mCursor = database.rawQuery("SELECT * FROM " + tableName + " LIMIT 0", null);
for (Field field : clazz.getDeclaredFields()) {
try {
DatabaseField annotationField = field.getAnnotation(DatabaseField.class);
if (annotationField != null && !annotationField.foreign()){
String columnName = field.getName();
boolean hasColumn = mCursor.getColumnIndex(columnName) != -1;
if (!hasColumn) {
String columnType = field.getType().getSimpleName();
if(columnType.equals(String.class.getSimpleName())){
columnType = "TEXT";
} else {
columnType = columnType.toUpperCase();
}
database.execSQL(MessageFormat.format("ALTER TABLE `{0}` ADD COLUMN {1} {2};", tableName, columnName, columnType));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
mCursor.close();
}
J'espère que ce code peut être meilleur.
Ici, je ne supprime pas les anciennes tables et colonnes qui ont été supprimées de dao, et je ne crée pas de champs étrangers (je ne suis pas sûr d’en avoir besoin).