【问题标题】:Bulk inserting using an array of ContentValues使用 ContentValues 数组批量插入
【发布时间】:2013-09-06 19:05:30
【问题描述】:

我正在尝试批量插入大约 700 个浮点数。我正在使用的方法如下,以及内容提供者的 bulkInsert。问题是,当我将所有浮点值放入 ContentValues 时,什么也没有发生。将这些浮点值插入 ContentValues 对象的更好方法是什么?

    private void saveToDatabase( float[] tempValues )
    {
    ContentValues values = new ContentValues();

    // WM: TODO: add patient id and sensor type
    for (float tempVal : tempValues){
        values.put( DataTable.COLUMN_DATA, tempVal );
    }

    ContentValues[] cvArray = new ContentValues[1];
    cvArray[0] = values;

    ContentResolver resolver = getContentResolver();
    resolver.bulkInsert( HealthDevContentProvider.CONTENT_URI_DATA, cvArray);

    public int bulkInsert(Uri uri, ContentValues[] values){
    int numInserted = 0;
    String table = null;

    int uriType = sURIMatcher.match(uri);

    switch (uriType) {
    case RAWINPUT_TABLE:
        table = RAWINPUT_TABLE_PATH;
        break;
    }

    db.beginTransaction();
    try {
        for (ContentValues cv : values) {
            long newID = db.insertOrThrow(table, null, cv);
            if (newID <= 0) {
                throw new SQLException("Failed to insert row into " + uri);
            }
        }
        db.setTransactionSuccessful();
        getContext().getContentResolver().notifyChange(uri, null);
        numInserted = values.length;
    } finally {         
        db.endTransaction();
    }
    return numInserted;
}

【问题讨论】:

    标签: android database android-contentprovider batch-insert


    【解决方案1】:

    我知道这会很粗鲁,但请扔掉这段代码。提供程序有处理大多数 SQLite 操作的主要方法,您尝试将其中三个(insert()、bulkInsert() 和 applyBatch())混合到某种科学怪人中。以下是主要错误:

    1) 这行values.put(DataTable.COLUMN_DATA, tempVal) 不会在每次迭代中插入新条目;它压倒了它们。在所有迭代之后,values 仅包含数组的第 700 个浮点值。

    2) 正如@Karakuri 记得的那样,cvArray 内部只有一个ContentValues 实例。 bulkInsert() doc 说明了它的第二个参数:

    An array of sets of column_name/value pairs to add to the database. This must not be null.
    

    所以cvArray 必须包含一个 ContentValues 实例(一个集合),用于您要插入数据库的每个条目。

    3) 不完全是错误,但您应该注意一些事情。不能保证mTables 会存在,并且尝试在不指定表的情况下进行操作将抛出SQLException

    4) 这三行基本没用:

    if (newId <= 0) {
        throw new SQLException("Failed to insert row into " + uri);
    }
    

    insertOrThrow() 如果在插入操作期间发生错误,则已经抛出异常。如果您想手动检查错误,请尝试 insert()insertWithOnConflict()(或在您的 try 块中添加一个 catch 并在那里处理异常)。

    5) 最后是numInserted@petey 指出的问题(无需重复)。

    最后一条建议:忘记bulkInsert() 的存在。我知道这将需要更多的代码行,但是使用applyBatch() 可以获得更好的结果(并且更容易,因为您不必实现它)。 Wolfram Rittmeyer写了一系列关于交易的优秀文章,有疑问请查看。

    最后但同样重要的是(是的,我今天心情很好),这就是我将如何对您的代码进行基本实现:

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        final SQLiteDatabase db // TODO: retrieve writable database
        final int match = matcher.match(uri);
    
        switch(match) {
            case RAWINPUT_TABLE:
                long id = db.insert(RAWINPUT_TABLE, null, values); // TODO: add catch block to deal.
                getContext().getContentResolver().notifyChange(uri, null, false);
                return ContentUris.withAppendedId(uri, id);
    
            default: 
                throw new UnsupportedOperationException("Unknown uri: " + uri);
        }
    }
    
    private void saveToDatabase( float[] tempValues ) {
    
        ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();
    
        for (float tempVal : tempValues){     
    
            operations.add(ContentProviderOperation
                            .newInsert(HealthDevContentProvider.CONTENT_URI_DATA)
                            .withValue(DataTable.COLUMN_DATA, tempVal).build();
                            .withValue() // TODO: add patient id
                            .withValue() // TODO: add sensor type);        
        }
    
    // WARNING!! Provider operations (except query if you are using loaders) happen by default in the main thread!!
    
        getContentResolver().applyBatch(operations); 
    } 
    

    【讨论】:

      【解决方案2】:

      我使用批量插入,不确定批量和批量之间的区别是什么,但我所做的就是这个

      ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();
      
      for(int j=0;j<locationAry.length;j++){
          ContentValues values2 = new ContentValues();
          values2.put(MapPoints.ELEMENT_ECM2ID, ecm2id);
          values2.put(MapPoints.ELEMENT_ID, newElementId);
          values2.put(MapPoints.LATITUDE, locationAry[j+1]);
          values2.put(MapPoints.LONGITUDE, locationAry[j]);
          values2.put(MapPoints.LAYER_ID, layerID);
          operations2.add(ContentProviderOperation.newInsert(MapPoints.CONTENT_URI).withValues(values2).build());
      
      
      }
      
      getContentResolver().applyBatch(MapElements.AUTHORITY, operations);
      

      您是否覆盖了 ContentProvider 中的 bulkInsert 方法?

      【讨论】:

      • bulkInsert:在单个 Uri 地址中插入任意数量的条目。 applyBatch:在多个 Uri 中进行任何 SQLite DML 操作(插入、删除、更新)。
      【解决方案3】:

      如果您希望每个浮点数在数据库中都有自己的记录,则需要为每个新记录创建一个 ContentValues 实例。现在,您有一个 ContentValues 实例,并且您正在向其写入相同的键(意味着您正在覆盖该值)700 次。

      private void saveToDatabase( float[] tempValues ) {
          final int count = tempValues.legnth;
          ContentValues[] cvArray = new ContentValues[count];
          for (int i = 0; i < count; i++) {
              float tempVal = tempValues[i];
              ContentValues values = new ContentValues();
              values.put( DataTable.COLUMN_DATA, tempVal );
              cvArray[i] = values;
          }
      
          /* all the rest */
      }
      

      【讨论】:

        【解决方案4】:

        如果一次插入失败,您的整个事务都会失败。如果没有看到您的表创建唯一键的语句,请在插入失败后尝试替换。此外,无论插入/替换失败,您的 numInserted 将始终与 values.length 相同。这似乎也不正确。

          ...
                db.beginTransaction();
                int numInserted = 0;
                try {
        
                    for (ContentValues cv : values) {
                        long newID;
                        try {
                            newID = database.insertOrThrow(table, null, cv);
                        } catch (SQLException ignore) {
                            newID = database.replace(table, null, cv);
                        }
                        if (newID <= 0) {
                            Log.e("TAG, "Failed to insert or replace row into " + uri);
                        } else {
                            // you are good...increment numInserted
                            numInserted++;
                        }
                    }
                    db.setTransactionSuccessful();
                    getContext().getContentResolver().notifyChange(uri, null);
        
                } finally {
                    db.endTransaction();
                }
                return numInserted;
        

        【讨论】:

          猜你喜欢
          • 2015-05-18
          • 1970-01-01
          • 2012-04-17
          • 2017-04-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多