使用 ContentProvider 插入多行

发布于 2024-11-26 16:40:19 字数 48 浏览 2 评论 0原文

我需要在一个事务中插入几行。我可以使用 ContentProvider 来实现吗?

I need to make insert of few rows in one transaction. Can I do it with ContentProvider?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

送舟行 2024-12-03 16:40:19

我已经在我的应用程序中实现了这一点,这是我使用的代码的要点。

在我的内容提供程序中,我重写了 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 没有问题。

I have implemented this in my app and here's the gist of the code that I use.

In my content provider, I have overridden the applyBatch() method and it's a very simple method to override:

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

The result is given to the next operation because you want to support back references. When I actually want to change stuff in the database in this single transaction I loop over my content and do stuff like this:

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

You just need to remember to finish by calling:

provider.applyBatch(operations);

This will perform your stuff in a single transaction and supports backreferences if you need the id from an earlier insert without issue.

地狱即天堂 2024-12-03 16:40:19

在客户端,ContentResolver 支持 bulkInsert() 方法。这些内容不一定会由 ContentProvider 在单个事务中进行处理,因为 ContentProvider 可能不执行任何事务。

On the client side, ContentResolver supports a bulkInsert() method. Those will not necessarily be processed in a single transaction by the ContentProvider, simply because there may not be any transactions performed by the ContentProvider.

温柔戏命师 2024-12-03 16:40:19

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

Here an example for 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;
}

And in your code something like:

/**
 * 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;
}
回首观望 2024-12-03 16:40:19

我还使用替换模式插入行 -
db.insertWithOnConflict(EVENT_TABLE_NAME, null, value, 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);

I also use replace mode for insert row -
db.insertWithOnConflict(EVENT_TABLE_NAME, null, value, SQLiteDatabase.CONFLICT_REPLACE);
Its will rid of conflict if record is exist already

In DatabaseHelper add 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;
        }

And call bulkInsert like this:

            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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文