Home » Android » android – Use Insert or Replace in ContentProvider

android – Use Insert or Replace in ContentProvider

Posted by: admin June 15, 2020 Leave a comment

Questions:

When I want to check and see if something exists in my ContentProvider what I usually do is something similar to this

Cursor c = getContentResolver().query(table,projection,selection,selectionArgs,sort);

if(c != null && c.moveToFirst()){

    //item exists so update

}else{

    //item does not exist so insert

}

but that means I always have to make possibly an unnecessary Database call slowing things down especially the greater number of checks on the database I need to do. There has to be a better way to handle this so I dont always have to query first.

I looked at this question

Android Contentprovider – update within an insert method

but using insertWithOnConflict only checks the primary key id and in my case that will not work because what I am checking is not the id but a unique string from a server database.

so is there something I can do with the Content Provider so I dont always have to make a query to check if the item exists in it already?

How to&Answers:

You can have UNIQUE constraint on columns different than ID one. Example:

CREATE TABLE TEST (_id INTEGER PRIMARY KEY AUTOINCREMENT,
server_id INTEGER NOT NULL, name TEXT, UNIQUE(server_id))

Having this table, in the insert method of your Content Provider you can do something like this:

@Override
    public Uri insert(Uri uri, ContentValues contentValues) {
        final SQLiteDatabase db = mDatabase.getWritableDatabase();
        final int match = mUriMathcer.match(uri);
        switch (match) {
            case TEST:
                insertOrUpdateById(db, uri, "TEST",
                        contentValues, "server_id");
                getContext().getContentResolver().notifyChange(uri, null, false);
                return Contract.Test.buildTestUri(contentValues.getAsString("server_id"));
            default:
                throw new UnsupportedOperationException("Unknown uri: " + uri);
        }
    }

/**
 * In case of a conflict when inserting the values, another update query is sent.
 *
 * @param db     Database to insert to.
 * @param uri    Content provider uri.
 * @param table  Table to insert to.
 * @param values The values to insert to.
 * @param column Column to identify the object.
 * @throws android.database.SQLException
 */
private void insertOrUpdateById(SQLiteDatabase db, Uri uri, String table,
                                ContentValues values, String column) throws SQLException {
    try {
        db.insertOrThrow(table, null, values);
    } catch (SQLiteConstraintException e) {
        int nrRows = update(uri, values, column + "=?",
                new String[]{values.getAsString(column)});
        if (nrRows == 0)
            throw e;
    }
}

I hope it helps. Cheers!

Answer:

Edy Bolos answer can be simply written as

CREATE TABLE TEST (
_id INTEGER PRIMARY KEY AUTOINCREMENT,
server_id INTEGER NOT NULL,
name TEXT UNIQUE ON CONFLICT REPLACE);

Add UNIQUE ON CONFLICT REPLACE in create table query.

Answer:

Edy Bolos answer can again be written as

private void insertOrUpdateById(SQLiteDatabase db, Uri uri, String table, 
                                ContentValues values, String column) 
             throws Exception {
    long id = db.insertWithOnConflict(table, column, values, 
                                      SQLiteDatabase.CONFLICT_REPLACE);
    if(id < 0){
        throw new Exception();
    }
}

Answer:

Use REPLACE INTO instead of INSERT INTO to solve the issue