2011-07-27 27 views
12

Tôi cần thực hiện chèn một vài hàng trong một giao dịch. Tôi có thể làm điều đó với ContentProvider không?Nhiều hàng được chèn với ContentProvider

+0

Câu hỏi là không rõ ràng .. dù sao đi nữa, bạn có thể xem tại đây 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

Trả lời

18

Ở phía máy khách, ContentResolver hỗ trợ phương thức bulkInsert(). Các giao dịch đó sẽ không nhất thiết được xử lý trong một giao dịch duy nhất theo số ContentProvider, đơn giản vì có thể không có bất kỳ giao dịch nào được thực hiện bởi ContentProvider.

+1

Như tôi hiểu, nếu nó không phải là o verrriden - nó sẽ chỉ gọi vài phương pháp 'chèn' standrt? – earsonheart

+2

Chính xác. Bạn không có ý tưởng nếu bất kỳ 'ContentProvider' đã cho ghi đè' bulkInsert() ', trừ khi nó là' ContentProvider' của riêng bạn. – CommonsWare

+0

Tôi nghĩ rằng bạn nên đi với ContentProviderOperations, đọc hướng dẫn này http://www.grokkingandroid.com/better-performance-with-contentprovideroperation/ –

21

Tôi đã thực hiện điều này trong ứng dụng của mình và đây là ý chính của mã mà tôi sử dụng.

Trong nhà cung cấp nội dung của tôi, tôi đã ghi đè phương pháp applyBatch() và đó là một phương pháp rất đơn giản để ghi đè lên:

/** 
* 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; 
} 

Kết quả được trao cho các hoạt động tiếp theo bởi vì bạn muốn hỗ trợ trở lại tài liệu tham khảo. Khi tôi thực sự muốn thay đổi nội dung trong cơ sở dữ liệu trong đơn giao dịch I vòng lặp này trong nội dung của tôi và làm công cụ như thế này:

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

Bạn chỉ cần nhớ để kết thúc bằng cách gọi:

provider.applyBatch(operations); 

này sẽ thực hiện công cụ của bạn trong một giao dịch duy nhất và hỗ trợ backreferences nếu bạn cần id từ một chèn trước đó mà không có vấn đề.

6

Dưới đây là một ví dụ cho 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; 
} 

Và trong một cái gì đó mã của bạn như:

/** 
* 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

Làm thế nào điều này tốt hơn so với gọi một chèn thường xuyên trong một vòng lặp từ mảng ban đầu của dữ liệu? Có lợi ích hiệu suất trong việc sử dụng BulkInsert không? –

+2

@AndrewS bulkInsert() là tốt hơn nhiều về các hoạt động lớn. Chỉ cần hoàn thành tối ưu hóa trong ứng dụng của tôi: applyBatch() với 2000 hoạt động trên một số bảng mất 2000 ms, 10 bulkInsert mất 100 ms. –

1

tôi cũng sử dụng thay thế chế độ cho chèn hàng - db.insertWithOnConflict (EVENT_TABLE_NAME, null , giá trị, SQLiteDatabase.CONFLICT_REPLACE); nó sẽ thoát khỏi xung đột nếu kỷ lục là tồn tại đã

Trong DatabaseHelper thêm INDEX UNIQUE

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

Và gọi bulkInsert như thế này:

  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); 
Các vấn đề liên quan