在ContentProvider中使用“插入”或“替换”

时间:2014-05-01 22:08:23

标签: android sqlite android-contentprovider

当我想检查并查看我的ContentProvider中是否存在某些内容时,我通常会做的与此相似

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

}

但这意味着我总是要做一个不必要的数据库调用,这会减慢速度,尤其是我需要对数据库进行更多的检查。必须有一个更好的方法来处理这个,所以我不必总是先查询。

我看了这个问题

Android Contentprovider - update within an insert method

但是使用insertWithOnConflict只检查主键ID,在我的情况下,这将无效,因为我检查的不是id,而是来自服务器数据库的唯一字符串。

所以我可以对内容提供商做些什么,所以我不必总是进行查询以检查项目是否已经存在?

4 个答案:

答案 0 :(得分:21)

您可以对不同于ID 1的列具有UNIQUE约束。例如:

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

拥有此表,在Content Provider的insert方法中,您可以执行以下操作:

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

我希望它有所帮助。干杯!

答案 1 :(得分:5)

Edy Bolos答案可以简单地写成

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

在创建表格查询中添加 UNIQUE ON CONFLICT REPLACE

答案 2 :(得分:1)

Edy Bolos的回答可以再次写成

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

答案 3 :(得分:0)

使用REPLACE INTO代替INSERT INTO来解决问题

相关问题