2011-07-27 47 views
12

我需要在一個事務中插入幾行。我可以用ContentProvider做到嗎?用ContentProvider插入多行

+0

問題不清楚..無論如何,你可以看看這裏的HTTP ://developer.android.com/guide/topics/providers/content-providers.html#modifying –

+0

http://stackoverflow.com/questions/5596354/insertion-of-thousands-of-contact-entries-using-applybatch -is-slow – Selvin

回答

18

在客戶端,ContentResolver支持bulkInsert()方法。這些將不一定由ContentProvider在一筆交易中處理,僅僅是因爲ContentProvider可能沒有執行任何交易。

+1

據我所知,如果不是o verrriden - 它只會叫幾個standrt'插入'方法? – earsonheart

+2

正確。你不知道是否有給定的'ContentProvider'重載'bulkInsert()',除非它是你自己的'ContentProvider'。 – CommonsWare

+0

我認爲你應該去ContentProviderOperations,閱讀本教程http://www.grokkingandroid.com/better-performance-with-contentprovideroperation/ –

21

我已經在我的應用程序中實現了這一點,這裏是我使用的代碼的要點。

在我的內容提供商,我已經覆蓋了applyBatch()方法,這是一個非常簡單的方法來覆蓋:因爲你要支持後向引用

/** 
* Performs the work provided in a single transaction 
*/ 
@Override 
public ContentProviderResult[] applyBatch(
     ArrayList<ContentProviderOperation> operations) { 
    ContentProviderResult[] result = new ContentProviderResult[operations 
      .size()]; 
    int i = 0; 
    // Opens the database object in "write" mode. 
    SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 
    // Begin a transaction 
    db.beginTransaction(); 
    try { 
     for (ContentProviderOperation operation : operations) { 
      // Chain the result for back references 
      result[i++] = operation.apply(this, result, i); 
     } 

     db.setTransactionSuccessful(); 
    } catch (OperationApplicationException e) { 
     Log.d(TAG, "batch failed: " + e.getLocalizedMessage()); 
    } finally { 
     db.endTransaction(); 
    } 

    return result; 
} 

結果是考慮到下一步的操作。當我其實是想在這單交易我遍歷我的內容改變的東西在數據庫中,做的東西是這樣的:

operations.add(ContentProviderOperation 
        .newInsert(
          Uri.withAppendedPath(
            NotePad.Notes.CONTENT_ID_URI_BASE, 
            Long.toString(task.dbId))) 
        .withValues(task.toNotesContentValues(0, listDbId)) 
        .build()); 
// Now the other table, use back reference to the id the note 
// received 
noteIdIndex = operations.size() - 1; 

operations.add(ContentProviderOperation 
        .newInsert(NotePad.GTasks.CONTENT_URI) 
        .withValues(task.toGTasksContentValues(accountName)) 
        .withValueBackReferences(
          task.toGTasksBackRefContentValues(noteIdIndex)) 
        .build()); 

你只需要記住通過調用來完成:

provider.applyBatch(operations); 

這將在單個事務中執行你的東西,並支持反向引用,如果你需要先前插入的ID沒有問題。

6

這裏的例如用於bulkInsert

/** 
* Perform bulkInsert with use of transaction 
*/ 
@Override 
public int bulkInsert(Uri uri, ContentValues[] values) { 
    int uriType = 0; 
    int insertCount = 0; 
    try { 

     uriType = sURIMatcher.match(uri); 
     SQLiteDatabase sqlDB = dbHelper.getWritableDatabase(); 

     switch (uriType) { 
     case MEASUREMENTS: 
      try { 
       sqlDB.beginTransaction(); 
       for (ContentValues value : values) { 
        long id = sqlDB.insert(Tab_Measurements.TABLE_NAME, null, value); 
        if (id > 0) 
         insertCount++; 
       } 
       sqlDB.setTransactionSuccessful(); 
      } catch (Exception e) { 
       // Your error handling 
      } finally { 
       sqlDB.endTransaction(); 
      } 
      break; 
     default: 
      throw new IllegalArgumentException("Unknown URI: " + uri); 
     } 
     // getContext().getContentResolver().notifyChange(uri, null); 
    } catch (Exception e) { 
     // Your error handling 
    } 

    return insertCount; 
} 

而在你的代碼是這樣的:

/** 
* Inserts new measurement information. 
* 
* @param ArrayList of measurements 
* @return number of inserted entries 
*/ 
public static long bulkInsertEntries(ArrayList<Item_Measurement> readings) { 
    // insert only if data is set correctly 
    if (readings.size() == 0) 
     return 0; 

    long insertCount = 0; 
    try { 
     // insert new entries 

     // ArrayList<ContentValues> valueList = new ArrayList<ContentValues>(); 
     ContentValues[] valueList = new ContentValues[readings.size()]; 
     int i = 0; 
     for (Item_Measurement reading : readings) { 
      ContentValues values = new ContentValues(); 
      values.put(COL_TIME_READING, reading.getTimeReading()); 
          // ... 
      valueList[i++] = values; 
     } 

     // returns ID 
     insertCount = ContentProviderOwn.getAppContext().getContentResolver() 
       .bulkInsert(ContentProviderOwn.MEASUREMENTS_URI_BASE, valueList); 

    } catch (Exception e) { 
     // Your error handling 
    } 
    return insertCount; 
} 
+0

這比在原始數據數組中循環調用常規插入更好嗎?使用BulkInsert有什麼性能好處? –

+2

@AndrewS bulkInsert()在大操作上要好得多。剛剛在我的應用程序中完成優化:applyBatch()在幾個表上執行2000次操作需要2000毫秒,10個bulkInsert執行100毫秒。 –

1

我也用替換模式,插入行 - db.insertWithOnConflict(EVENT_TABLE_NAME,空,值,SQLiteDatabase.CONFLICT_REPLACE); 它會擺脫衝突的,如果記錄已經存在

在DatabaseHelper添加UNIQUE INDEX

public class DataProvider extends ContentProvider { 

    private static class DatabaseHelper extends SQLiteOpenHelper { 
     DatabaseHelper(Context context){ 
      super(context, DATABASE_NAME, null, DATABASE_VERSION); 
     } 

     @Override 
     public void onCreate(SQLiteDatabase db){ 
      db.execSQL(CREATE_EVENT_TABLE); 
      db.execSQL("CREATE UNIQUE INDEX event_idx ON " + EVENT_TABLE_NAME + " (" + EventTable.EVENT_ID + ")"); 
// ... 

     ... 
     @Override 
     public int bulkInsert(Uri uri, ContentValues[] values) { 
      Log.i(TAG, "bulkInsert"); 
      if (values.length == 0) 
       return 0; 
      int insertCount = 0; 
      try { 
       switch (uriMatcher.match(uri)) { 
        case EVENT_LIST: 
         try { 
          db.beginTransaction(); 
          for (ContentValues value : values) { 
           long id = db.insertWithOnConflict(EVENT_TABLE_NAME, null, value, SQLiteDatabase.CONFLICT_REPLACE); 
           if (id > 0) 
            insertCount++; 
          } 
          db.setTransactionSuccessful(); 
         } catch (Exception e) { 
          // Your error handling 
         } finally { 
          db.endTransaction(); 
         } 
         break; 
        default: 
         throw new IllegalArgumentException("Unknown URI " + uri); 
       } 
       getContext().getContentResolver().notifyChange(uri, null); 
      } catch (Exception e) { 
       Log.i(TAG, "Exception : " + e); 
      } 
      return insertCount; 
     } 

並調用bulkInsert這樣的:

  ContentValues[] cvArr = new ContentValues[eventList.size()]; 
      long insertCount = 0; 
      int i = 0; 
      for (Event event : eventList) { 
       ContentValues cv = new ContentValues(); 
       cv.put(DataProvider.EventTable.EVENT_ID, event.id); 
       cv.put(DataProvider.EventTable.SENSOR_ID, event.sensor_id); 
       cv.put(DataProvider.EventTable.TIMESTAMP, event.time); 
       cvArr[i++] = cv; 
      } 
      // returns ID 
      insertCount = context.getContentResolver() 
        .bulkInsert(DataProvider.CONTENT_EVENT_LIST, cvArr);