2014-05-01 71 views
7

替換當我要檢查,看看是否在我的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,但是從一個唯一的字符串服務器數據庫

那麼有什麼我可以用內容提供商做的事情,所以我並不總是必須做一個查詢來檢查它是否已經存在它的項目?

+0

你知道 「UPSERT」 命令的**更換**? https://www.sqlite.org/lang_replace.html - 它插入一條新記錄(如果不存在或者它更新現有記錄)。 –

+0

@BobMalooga不,我不知道這一點,但你可以在'ContentProvider'中使用它嗎?所有內容提供商都有插入,更新,替換或刪除 – tyczj

+0

@tyczi否...抱歉,我不知道ContentProvider限制。我以爲你可以分別使用rawQuery或execSQL來獲取和設置數據。現在看來ContentProvider很遺憾不提供這些功能。所以 - 我從內容提供商那裏瞭解了一些有關內容(從未使用 - 並且可能會在未來跳過)。你現在知道SQLite提供了「upserts」。 ;) –

回答

19

對不同於ID的列可以具有UNIQUE約束。例如:

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

有了這個表,在您的內容提供商的插入方法,你可以做這樣的事情:

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

我希望它能幫助。乾杯!

+0

這是一個獨創的想法 - 正是我一直在尋找的。 Thankyou,非常感謝。我贊成你。 – DEzra

+0

如果我想在插入記錄時返回* Uri *,我應該怎麼做,Uri必須使用'Inserted Id'創建。 ''_id' –

5

伊迪Bolos答案可以簡單地寫爲

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

添加UNIQUE ON CONFLICT替換創建表查詢

+5

這不一樣,因爲'ON CONFLICT REPLACE'會替換整行,可能會丟失一些列,而我的解決方案會更新您指定的列,而不會丟失其他數據列。 –

1

伊迪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

這不一樣,因爲'ON CONFLICT REPLACE'會替換整行,可能會丟失一些列,而我的解決方案會更新您指定的列,而不會丟失其他列中的數據。 –

相關問題