3

我正在尝试批量插入大约 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;
}
4

4 回答 4

3

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

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

2)正如@Karakuri 记得的那样,里面只有一个ContentValues实例cvArraybulkInsert()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)最后,@petey 指出了问题numInserted(无需重复)。

最后一条建议:忘记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); 
} 
于 2013-09-20T18:23:33.830 回答
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);

您是否覆盖了bulkInsertContentProvider 中的方法?

于 2013-09-06T19:17:52.510 回答
2

如果您希望每个浮点数在数据库中都有自己的记录,则需要为每个新记录创建一个 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 */
}
于 2013-09-06T20:27:11.280 回答
0

如果一个插入失败,你的整个事务就会失败。如果没有看到您的表创建唯一键的语句,请在插入失败后尝试替换。而且无论插入/替换失败,您的 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;
于 2013-09-06T19:27:12.947 回答