Android/SQLite: Insert-Update table columns to keep the identifier

前端 未结 6 1093
眼角桃花
眼角桃花 2020-12-13 19:39

Currently, I am using the following statement to create a table in an SQLite database on an Android device.

CREATE TABLE IF NOT EXISTS \'locations\' (
  \'_i         


        
6条回答
  •  刺人心
    刺人心 (楼主)
    2020-12-13 20:11

    I can understand the perceived notion that it is best for performance to do all this logic in SQL, but perhaps the simplest (least code) solution is the best one in this case? Why not attempt the update first, and then use insertWithOnConflict() with CONFLICT_IGNORE to do the insert (if necessary) and get the row id you need:

    public Uri insert(Uri uri, ContentValues values) {
        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        String selection = "latitude=? AND longitude=?"; 
        String[] selectionArgs = new String[] {values.getAsString("latitude"),
                    values.getAsString("longitude")};
    
        //Do an update if the constraints match
        db.update(DatabaseProperties.TABLE_NAME, values, selection, null);
    
        //This will return the id of the newly inserted row if no conflict
        //It will also return the offending row without modifying it if in conflict
        long id = db.insertWithOnConflict(DatabaseProperties.TABLE_NAME, null, values, CONFLICT_IGNORE);        
    
        return ContentUris.withAppendedId(uri, id);
    }
    

    A simpler solution would be to check the return value of update() and only do the insert if the affected count was zero, but then there would be a case where you could not obtain the id of the existing row without an additional select. This form of insert will always return to you the correct id to pass back in the Uri, and won't modify the database more than necessary.

    If you want to do a large number of these at once, you might look at the bulkInsert() method on your provider, where you can run multiple inserts inside a single transaction. In this case, since you don't need to return the id of the updated record, the "simpler" solution should work just fine:

    public int bulkInsert(Uri uri, ContentValues[] values) {
        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        String selection = "latitude=? AND longitude=?";
        String[] selectionArgs = null;
    
        int rowsAdded = 0;
        long rowId;
        db.beginTransaction();
        try {
            for (ContentValues cv : values) {
                selectionArgs = new String[] {cv.getAsString("latitude"),
                    cv.getAsString("longitude")};
    
                int affected = db.update(DatabaseProperties.TABLE_NAME, 
                    cv, selection, selectionArgs);
                if (affected == 0) {
                    rowId = db.insert(DatabaseProperties.TABLE_NAME, null, cv);
                    if (rowId > 0) rowsAdded++;
                }
            }
            db.setTransactionSuccessful();
        } catch (SQLException ex) {
            Log.w(TAG, ex);
        } finally {
            db.endTransaction();
        }
    
        return rowsAdded;
    }
    

    In truth, the transaction code is what makes things faster by minimizing the number of times the database memory is written to the file, bulkInsert() just allows multiple ContentValues to be passed in with a single call to the provider.

提交回复
热议问题