Android / SQLite: Einfügen-Aktualisieren von Tabellenspalten, um die ID beizubehalten

Derzeit verwende ich die folgende Anweisung, um eine Tabelle in einer SQLite-Datenbank auf einem Android-Gerät zu erstellen.

CREATE TABLE IF NOT EXISTS 'locations' (
  '_id' INTEGER PRIMARY KEY AUTOINCREMENT, 'name' TEXT, 
  'latitude' REAL, 'longitude' REAL, 
  UNIQUE ( 'latitude',  'longitude' ) 
ON CONFLICT REPLACE );

Die Konfliktklausel am Ende bewirkt, dass Zeilen sindfallen gelassen wenn neue Einfügungen mit denselben Koordinaten vorgenommen werden. DasSQLite-Dokumentation enthält weitere Informationen zur Konfliktklausel.

Stattdessen würde ich gernebehalten die ehemaligen Reihen und geradeaktualisieren ihre Spalten. Was ist der effizienteste Weg, um dies in einer Android / SQLite-Umgebung zu tun?

Als Konfliktklausel in derCREATE TABLE Aussage.Als einINSERT auslösen.Als Vorbehaltsklausel imContentProvider#insert Methode.... besser kann man nicht denken

Ich denke, es ist performanter, solche Konflikte in der Datenbank zu behandeln. Außerdem fällt es mir schwer, das umzuschreibenContentProvider#insert Methode zur Berücksichtigung derInsert-Update Szenario. Hier ist der Code voninsert Methode:

public Uri insert(Uri uri, ContentValues values) {
    final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
    long id = db.insert(DatabaseProperties.TABLE_NAME, null, values);
    return ContentUris.withAppendedId(uri, id);
}

Wenn Daten vom Backend ankommen, füge ich die Daten wie folgt ein.

getContentResolver.insert(CustomContract.Locations.CONTENT_URI, contentValues);

Ich habe Probleme, herauszufinden, wie ich einen alternativen Aufruf anwenden kannContentProvider#update Hier. Außerdem ist dies sowieso nicht meine bevorzugte Lösung.

Bearbeiten:

@ CommonsWare: Ich habe versucht, Ihren Vorschlag umzusetzenINSERT OR REPLACE. Ich habe mir diesen hässlichen Code ausgedacht.

private static long insertOrReplace(SQLiteDatabase db, ContentValues values, String tableName) {
    final String COMMA_SPACE = ", ";
    StringBuilder columnsBuilder = new StringBuilder();
    StringBuilder placeholdersBuilder = new StringBuilder();
    List<Object> pureValues = new ArrayList<Object>(values.size());
    Iterator<Entry<String, Object>> iterator = values.valueSet().iterator();
    while (iterator.hasNext()) {
        Entry<String, Object> pair = iterator.next();
        String column = pair.getKey();
        columnsBuilder.append(column).append(COMMA_SPACE);
        placeholdersBuilder.append("?").append(COMMA_SPACE);
        Object value = pair.getValue();
        pureValues.add(value);
    }
    final String columns = columnsBuilder.substring(0, columnsBuilder.length() - COMMA_SPACE.length());
    final String placeholders = placeholderBuilder.substring(0, placeholdersBuilder.length() - COMMA_SPACE.length());
    db.execSQL("INSERT OR REPLACE INTO " + tableName + "(" + columns + ") VALUES (" + placeholders + ")", pureValues.toArray());

    // The last insert id retrieved here is not safe. Some other inserts can happen inbetween.
    Cursor cursor = db.rawQuery("SELECT * from SQLITE_SEQUENCE;", null);
    long lastId = INVALID_LAST_ID;
    if (cursor != null && cursor.getCount() > 0 && cursor.moveToFirst()) {
        lastId = cursor.getLong(cursor.getColumnIndex("seq"));
    }
    cursor.close();
    return lastId;
}

Wenn ich die SQLite-Datenbank überprüfe, sind jedoch gleiche Spaltennoch entfernt und mit neuen IDs eingefügt. Ich verstehe nicht warum das passiert und dachte der Grund ist meine Konfliktklausel. Aber dieDokumentation sagt das Gegenteil.

Der in der OR-Klausel eines INSERT oder UPDATE angegebene Algorithmusüberschreibt Jeder in einer CREATE TABLE angegebene Algorithmus. Wenn nirgendwo ein Algorithmus angegeben ist, wird der ABORT-Algorithmus verwendet.

Ein weiterer Nachteil dieses Versuchs besteht darin, dass Sie den Wert der ID verlieren, die von einer insert-Anweisung zurückgegeben wird. Um dies auszugleichen, habe ich endlich eine Möglichkeit gefunden, nach dem zu fragenlast_insert_rowid. Es ist wie erklärtin den posten von dtmilano und swiz. Ich bin mir jedoch nicht sicher, ob dies sicher ist, da ein anderer Einsatz dazwischen passieren kann.

Antworten auf die Frage(5)

Ihre Antwort auf die Frage