Android / SQLite: вставьте-обновите столбцы таблицы, чтобы сохранить идентификатор

В настоящее время я использую следующий оператор для создания таблицы в базе данных SQLite на устройстве Android.

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

Предложение конфликта в конце приводит к тому, что строкиdropped когда новые вставки сделаны с такими же координатами.Документация по SQLite содержит дополнительную информацию о конфликтной оговорке.

Вместо этого я хотел быkeep бывшие ряды и простоupdate их столбцы. Каков наиболее эффективный способ сделать это в среде Android / SQLite?

As a conflict-clause in the CREATE TABLE statement. As an INSERT trigger. As a conditional clause in the ContentProvider#insert method. ... any better you can think off

Я думаю, что более эффективно обрабатывать такие конфликты в базе данных. Кроме того, мне трудно переписатьContentProvider#insert метод для рассмотренияinsert-update сценарий. Вот кодinsert метод:

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);
}

Когда данные поступают из бэкэнда, все, что я делаю, это вставляю данные следующим образом.

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

У меня проблемы с выяснением, как применить альтернативный вызов кContentProvider#update Вот. Кроме того, это не мое любимое решение в любом случае.

Edit:

@CommonsWare: я пытался реализовать ваше предложение использоватьINSERT OR REPLACE, Я придумал этот уродливый кусок кода.

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;
}

Однако при проверке базы данных SQLite равные столбцыstill removed and inserted with new ids, Я не понимаю, почему это происходит, и подумал, что причина в моем конфликте. Нодокументация утверждает обратное.

The algorithm specified in the OR clause of an INSERT or UPDATE overrides any algorithm specified in a CREATE TABLE. If no algorithm is specified anywhere, the ABORT algorithm is used.

Другим недостатком этой попытки является то, что вы теряете значение идентификатора, которое возвращается оператором вставки. Чтобы компенсировать это, я наконец нашел возможность попроситьlast_insert_rowid, Это как объяснилив постах dtmilano и swiz, Однако я не уверен, что это безопасно, поскольку между ними может произойти еще одна вставка.

Ответы на вопрос(5)

Ваш ответ на вопрос