comme on peut le voir dans la documentation, la syntaxe à faire pour insérer ou mettre à jour est la suivante: INSERT OR REPLACE INTO <table> (<columns>) VALUES (<values>)
, ma question est-il une fonction qui fusionne le suivant?
public long insert (String table, String nullColumnHack, ContentValues values)
public int update (String table, ContentValues values, String whereClause, String[] whereArgs)
ou doit-il être fait avec une instruction SQL préparée et rawQuery?
Quelles sont les meilleures pratiques pour effectuer une insertion ou une mise à jour sous Android?
Je crois que vous demandez comment INSÉRER de nouvelles lignes ou METTRE À JOUR vos lignes existantes en une seule étape. Bien que cela soit possible dans un seul SQL brut, comme indiqué dans la section cette réponse , j’ai trouvé qu’il était plus facile de le faire en deux étapes dans Android utilisant SQLiteDatabase .insertWithOnConflict () en utilisant CONFLICT_IGNORE pour conflictAlgorithm.
ContentValues initialValues = new ContentValues();
initialValues.put("_id", 1); // the execution is different if _id is 2
initialValues.put("columnA", "valueNEW");
int id = (int) yourdb.insertWithOnConflict("your_table", null, initialValues, SQLiteDatabase.CONFLICT_IGNORE);
if (id == -1) {
yourdb.update("your_table", initialValues, "_id=?", new String[] {"1"}); // number 1 is the _id here, update to variable for your code
}
Cet exemple suppose que la clé de table est définie pour la colonne "_id", que vous connaissez l'enregistrement _id et qu'il existe déjà la ligne n ° 1 (_id = 1, columnA = "valueA", columnB = "valueB"). Voici la différence utilisant insertWithOnConflict avec CONFLICT_REPLACE et CONFLICT_IGNORE
Lorsque vous essayez d'insérer la nouvelle ligne n ° 2 qui n'existe pas encore, le code n'exécutera l'insert SQL que dans la première instruction insertWithOnConflict (le résultat sera _id = 2, columnA = "valueNEW", columnB = NULL).
Faites attention à ce bogue qui est à l'origine du dysfonctionnement de SQLiteDatabase.CONFLICT_IGNORE sur API10 (et probablement API11). La requête renvoie 0 au lieu de -1 lorsque je teste sur Android 2.2.
Si vous ne connaissez pas la clé d'enregistrement _id ou si vous avez une condition qui ne créera pas de conflit, vous pouvez inverser la logique en UPDATE ou INSERT . Ceci gardera votre clé d'enregistrement _id lors de la mise à jour ou créera un nouvel enregistrement _id lors de l'insertion.
int u = yourdb.update("yourtable", values, "anotherID=?", new String[]{"x"});
if (u == 0) {
yourdb.insertWithOnConflict("yourtable", null, values, SQLiteDatabase.CONFLICT_REPLACE);
}
L'exemple ci-dessus suppose que vous souhaitez simplement mettre à jour la valeur de l'horodatage dans l'enregistrement, par exemple. Si vous appelez d'abord insertWithOnConflict, INSERT créera un nouvel enregistrement _id en raison de la différence dans la condition d'horodatage.
c'est votre méthode SQLiteDatabase.insertWithOnConflict () . comprendre ce à quoi il fait référence ce document sur sqlite
SQLiteDatabase.replace () le fait, il appelle essentiellement:
insertWithOnConflict(table, nullColumnHack, initialValues, CONFLICT_REPLACE);
Dommage que la documentation ne soit pas très claire.
Le nom de l'opération pour cela est "upsert" et sa solution consiste à identifier les colonnes de votre table qui rendent une ligne UNIQUE.
Exemple: _id, name, job, hours_worked
Les colonnes que nous utiliserons sont name et job.
private int getID(String name, String job){
Cursor c = dbr.query(TABLE_NAME,new String[]{"_id"} "name =? AND job=?",new String[]{name,job},null,null,null,null);
if (c.moveToFirst()) //if the row exist then return the id
return c.getInt(c.getColumnIndex("_id"));
return -1;
}
Dans votre classe de gestionnaire de base de données:
public void upsert(String name, String job){
ContentValues values = new ContentValues();
values.put("NAME",name);
values.put("JOB",job);
int id = getID(name,job);
if(id==-1)
db.insert(TABLE_NAME, null, values);
else
db.update(TABLE_NAME, values, "_id=?", new String[]{Integer.toString(id)});
}
SQLiteDatabase.replace () est probablement ce que vous recherchez. Je ne l'ai pas essayé, mais le doc dit qu'il renvoie l'ID de ligne de la nouvelle ligne insérée , afin que cela puisse fonctionner.
J'avais le même problème, mais je me suis rendu compte que quand mon objet a déjà un identifiant, il devrait être mis à jour et quand il n'a pas d'identifiant, il devrait être inséré, c'est donc étape par étape ce que j'ai fait pour résoudre le problème:
1- dans votre objet getId utilisez Integer ou initialisez l'ID comme bon vous semble: voici mon code
public Integer getId() {
return id;
}
2- Vérifiez l’id de votre méthode pour l’insertion ou la mise à jour après avoir tout mis dans ContentValues:
if(myObject.getId()!= null ){
int count = db.update(TABLE_NAME,myContentValues,ID + " = ? ",
new String[]{String.valueOf(myObject.getId())});
if(count<=0){
//inserting content values to db
db.insert(TABLE_NAME, null, myContentValues);
}
} else {
db.insert(TABLE_NAME, null, myContentValues);
}
ce qui se passe ici, c’est que je vérifie la présence d’un identifiant si j’ai mis à jour cette ligne, mais si la méthode update renvoie -1, cela signifie qu’il n’y avait pas de rangée portant cet identifiant; j’insère donc cette rangée.
j'espère que cela t'aides.
Qu'en est-il de replaceOrThrow (Table de chaînes, String nullColumnHack, ContentValues initialValues)
La documentation dit ... Méthode pratique pour remplacer une ligne dans la base de données. Insère une nouvelle ligne si une ligne n'existe pas déjà.
Fondamentalement, il appelle insertWithOnConflict