48 votes

SQLiteOpenHelper onUpgrade () Confusion Android

Je suis en train de faire ma première application avec une base de données et je vais avoir un peu de mal à comprendre le onUpgrade fonction. Ma base de données dispose d'une table avec des objets et l'un des favoris de la colonne, de sorte que l'utilisateur peut préférée d'un élément. La plupart des implémentations, je vois tout simplement de supprimer la table et de le reconstruire, mais je ne veux pas faire ça. Je veux être en mesure d'ajouter plus d'articles pour la table.

Lorsque l'application est mis à jour à travers le marché android la base de données de connaître son numéro de version? Donc, pourrais-je incrémenter le numéro de version dans le code, puis de les exporter vers le marché et lorsque l'utilisateur démarre la version mise à niveau pour la première fois, puis onUpgrade sera appelé?

Si c'est le cas, mon onUpgrade serait tout simplement de tirer à partir d'un fichier et l'ajouter à la base de données articles. Est-ce une façon habituelle de faire les choses ou est-il une meilleure façon de traiter ce Android. J'essaie de rester le plus standard possible.

Merci

108voto

Pentium10 Points 68884

Ok, avant de vous lancer dans de gros problèmes, vous devriez savoir que SQLite est limitée sur la commande ALTER TABLE, il permet d' add et rename seulement de ne pas supprimer/supprimer ce qui est fait avec les loisirs de la table.

Vous devez toujours avoir la nouvelle création de la table de la requête à la main, et l'utiliser pour la mise à niveau et le transfert de toutes les données existantes. Remarque: notez que l'onUpgrade méthodes de pistes pour votre sqlite objet d'assistance et vous avez besoin pour gérer toutes les tables.

Quel est donc recommandé onUpgrade:

  • beginTransaction
  • exécuter une création de la table avec if not exists (nous faisons une mise à niveau, de sorte que le tableau pourrait n'existe pas encore, ce sera un échec alter et drop)
  • mettre dans une liste les colonnes existantes List<String> columns = DBUtils.GetColumns(db, TableName);
  • table de sauvegarde (ALTER table " + TableName + " RENAME TO 'temp_" + TableName)
  • créer une table (la plus récente création de la table de schéma)
  • obtenez de l'intersection avec les nouvelles colonnes, cette fois, les colonnes prises à partir de la mise à jour de la table (columns.retainAll(DBUtils.GetColumns(db, TableName));)
  • la restauration des données (String cols = StringUtils.join(columns, ","); db.execSQL(String.format( "INSERT INTO %s (%s) SELECT %s from temp_%s", TableName, cols, cols, TableName)); )
  • supprimez la sauvegarde de la table (DROP table 'temp_" + TableName)
  • setTransactionSuccessful

(Ce n'est pas la poignée de la table de downgrade, si vous renommer une colonne, vous n'obtenez pas les données transférées noms de colonnes ne correspondent pas).

.

public static List<String> GetColumns(SQLiteDatabase db, String tableName) {
    List<String> ar = null;
    Cursor c = null;
    try {
        c = db.rawQuery("select * from " + tableName + " limit 1", null);
        if (c != null) {
            ar = new ArrayList<String>(Arrays.asList(c.getColumnNames()));
        }
    } catch (Exception e) {
        Log.v(tableName, e.getMessage(), e);
        e.printStackTrace();
    } finally {
        if (c != null)
            c.close();
    }
    return ar;
}

public static String join(List<String> list, String delim) {
    StringBuilder buf = new StringBuilder();
    int num = list.size();
    for (int i = 0; i < num; i++) {
        if (i != 0)
            buf.append(delim);
        buf.append((String) list.get(i));
    }
    return buf.toString();
}

39voto

pjv Points 4527

À côté de Pentium10 excellente réponse, voici quelques bons exemples de la vie code:

6voto

factslist.org Points 351

Merci de préciser que onUpgrade() ne sera pas de Supprimer/Drop @Pentium 10

Pour ceux d'entre vous qui voudraient connaître le moment exact de onUpgrade() est appelée, elle est au cours d'un appel soit à getReadableDatabase() ou getWriteableDatabase().

Pour ceux qui ne sont pas clairement comment il s'assurer qu'elle est déclenchée...la réponse est: Elle est déclenchée lorsque la version de base de données fourni par le constructeur de SqLiteOpenHelper est mis à jour. Voici un exemple

public class dbSchemaHelper extends SQLiteOpenHelper {

private String sql;
private final String D_TAG = "FundExpense";
//update this to get onUpgrade() method of sqliteopenhelper class called
static final int DB_VERSION = 2; 
static final String DB_NAME = "fundExpenseManager";

public dbSchemaHelper(Context context) {
    super(context, DB_NAME, null, DB_VERSION);
    // TODO Auto-generated constructor stub
}

maintenant à...onUpgrade()

@Override
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
    sql = "ALTER TABLE " + fundExpenseSchema.Expense.TABLE_NAME + " ADD COLUMN " + fundExpenseSchema.Expense.FUNDID + " INTEGER";
    arg0.execSQL(sql);
}

1voto

JavierSP1209 Points 155

J'ai été en utilisant la solution proposée par @Pentium10 pour un long temps, mais aujourd'hui j'ai eu un problème, après avoir fait la commande alter table, getColumns de la table d'origine renvoie toujours les mêmes colonnes (dans la nouvelle version de la db de la table de souffrir maire de modification de la structure, certaines colonnes ajouté quelques autres), vraiment je ne sais pas pourquoi instruction select ne reflète pas les changements de structure, plus de plus avant de créer ma table, encore une fois, l'instruction select renvoie toujours les colonnes! Lorsque la table n'est pas re-créé encore!

J'ai donc gérer la résolution de ce problème de mise à jour getColumns méthode à l'aide d' pragma table_info, comme ceci:

    /**
 * Get a list of column base_dictionary for the selected table
 *
 * @param db
 *  Database that contains the table
 * @param tableName
 *  Table name to be used
 * @return A List of column name
 */
public static List<String> getColumns(SQLiteDatabase db, String tableName) {
    List<String> ar = null;
    Cursor c = null;
    try {
        c = db.rawQuery("pragma table_info(" + tableName + ")", null);

        ar = new ArrayList<String>();
        if (c != null && c.moveToFirst()) {
            do {
                ar.add(c.getString(c.getColumnIndexOrThrow("name")));
            } while (c.moveToNext());
            c.close();
        }

    } catch (Exception e) {
        Log.v(tableName, e.getMessage(), e);
        e.printStackTrace();
    } finally {
        if (c != null) c.close();
    }
    return ar;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X