4

我正在实现一个 PRIVATE ContentProvider,它的关系表很少(一对多,多对多)。在我当前的实现中,所有表都可以通过 URI 访问。如何简化界面,使 URI 不必访问内部“直通”表?

比如我有一个POSTS表,每个POST通过TAGGINGS表有很多TAGS。我只想与 POSTS URI 交互并在ContentProvider.

因为query它很容易返回一个带有连接表的游标,但是我该怎么做insert呢?bulkInsert我应该调查什么?

4

4 回答 4

7

这是一个限制ContentProvider。如果您不将数据暴露给其他应用程序,则可以使用自定义数据库适配器实现,方法和查询直接满足您的要求。

bulkInsert()在这种情况下无济于事,因为它一次只将行插入到一个表中。但是看看ContentProvider.applyBatch()方法和ContentProviderOperationContentProviderOperation.Builder类(您可能需要withValueBackReference()一对多插入)。

这些链接应该可以帮助您了解如何使用它们:

http://www.grokkingandroid.com/better-performance-with-contentprovideroperation/ http://www.grokkingandroid.com/androids-contentprovideroperation-withbackreference-explained/ withValueBackReference 的语义是什么?

但是请注意,使用ContentProviderOperationbulkInsert()一次插入多行要慢得多,因为它Uri会在每次执行操作时解析(字符串比较)。这样做您仍然必须公开 Uri 才能插入到子表中。

如果您决定使用applyBatch(),请在您的提供程序中覆盖它,以便它在一个事务中执行所有操作,从而保持数据的一致性并加快数据库操作:

@Override
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
        throws OperationApplicationException {
    final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
    db.beginTransaction();
    try {
        ContentProviderResult[] results = super.applyBatch(operations);
        db.setTransactionSuccessful();
        return results;
    } finally {
        db.endTransaction();
    }
}
于 2012-07-15T13:30:57.900 回答
1

只要提供了所需的值,您就可以自由地插入到乘法表中。

例如:

ContentValues v = new ContentValues();
v.put("title","post1");
v.put("tag","tag1");
getProvider().insert(POST_URI,v);

在 实现 中insert, 可以 检查 是否 存在tag属于 其他 表 的 字段 ( ) 是否 存在 , 如果 存在 , 则 意味着 你 应该 做 额外 的 工作 -- 如果 标签 不 存在 则 先 插入 , 建立 标签 与 帖子 之间 的 正确 关联 .刚插入。

您可以查看android联系人的源代码以供参考。

更新:

要插入多个标签,一种 hack-y 方法是插入逗号分隔的字符串。这并不优雅,但它有效。

于 2012-07-15T13:30:22.580 回答
1

只是为了做到这一点:您想拥有一个 URI 并通过对 ContentProvider 的一次插入调用插入一篇文章及其所有标签?正确的?

问题是,您需要在 ContentValues 对象中包含所有值。数据库标准化是有原因的。尽管如此,它可能是可行的。对于标签,这应该很容易。只需对所有标签使用一个字符串。例如“android、ios、bada、wp7”并在您的插入方法中解析此字符串。

您还可以使用命名加整数约定。只要存在 tag1、tag2、... tagX,您就可以从 ContentProvider 的 insert 方法中读取这些值。

两者都不优雅,但会起作用。

在这种情况下,bulkInsert 或 applyBatch 在您的代码中没有位置。如果您想在一个事务中一次使用多个对 ContentProvider 的调用,它们只会发挥作用。

但我认为更好的解决方案确实是实际使用 biegleux 描述的多个操作。

于 2012-07-17T16:22:28.083 回答
0

由于您将要插入多个表,因此正常的SQLiteDatabase.insert辅助函数将不起作用。但这以一种高性能和好的方式是完全可行的。

您需要从将要插入您的 ContentProvider 的用户的端点查看这一点,即使它只是您自己。因此,首先为所有字段定义名称或键。由于您不会使用SQLiteDatabase.insert,因此实际上不需要将它们命名为与数据库字段相同的名称。所有名称都不应重复。例如,如果您有两个不同表中的字段可能tagTableA和 中重叠,TableB您可以将这些字段的名称定义为TableA.tagTableB.tag。或者对不冲突的更具描述性的名称使用语义命名。

接下来,您需要使用SQLiteStatementper this answer创建插入查询。确保您使用的名称createInsert与 ContentProvider 的调用者用作 ContentValues 中的键的名称相同。

于 2014-09-11T07:21:33.950 回答