Android 使用ContentProvider插入多个表
我正在实现一个私有的Android 使用ContentProvider插入多个表,android,android-contentprovider,android-contentresolver,android-sqlite,Android,Android Contentprovider,Android Contentresolver,Android Sqlite,我正在实现一个私有的ContentProvider,它有几个具有关系的表(一对多,多对多)。在我当前的实现中,URI可以访问所有表。 如何简化接口,使内部“直通”表不必被URI访问 例如,我有一个POSTS表,通过TAGGINGS表,每个POST都有许多标记。 我只想与postsuri交互,并在ContentProvider中执行“私有”工作 对于query来说,返回带有联接表的游标很简单,但是如何使用insert执行此操作?bulkInsert是我应该研究的吗?只要提供了所需的值,您就可以自由
ContentProvider
,它有几个具有关系的表(一对多,多对多)。在我当前的实现中,URI可以访问所有表。
如何简化接口,使内部“直通”表不必被URI访问
例如,我有一个POSTS表,通过TAGGINGS表,每个POST都有许多标记。
我只想与postsuri交互,并在ContentProvider
中执行“私有”工作
对于
query
来说,返回带有联接表的游标很简单,但是如何使用insert
执行此操作?bulkInsert
是我应该研究的吗?只要提供了所需的值,您就可以自由插入乘法表
例如:
ContentValues v = new ContentValues();
v.put("title","post1");
v.put("tag","tag1");
getProvider().insert(POST_URI,v);
在insert
的实现中,您可以检查字段(tag
)是否属于其他表。如果属于其他表,则意味着您应该做额外的工作-首先插入标记如果不存在,请在标记和刚插入的帖子之间建立正确的关联
您可以查看android联系人的源代码以供参考
更新:
要插入多个标记,一种常见的方法是插入逗号分隔的字符串。这并不优雅,但它可以工作。这是
内容提供者的一个限制。如果不将数据公开给其他应用程序,则可以使用自定义数据库适配器实现,方法和查询直接满足您的要求
bulkInsert()
在这种情况下没有帮助,因为它一次只在一个表中插入行。但请看一下方法和类(对于一对多插入,您可能需要with valuebackreference()
)
这些链接应有助于您了解如何使用它们:
但是请注意,如果一次插入多行,使用ContentProviderOperation
要比bulkInsert()
慢得多,因为每次执行操作时,它都会解析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();
}
}
@覆盖
public ContentProviderResult[]applyBatch(ArrayList操作)
抛出操作应用程序异常{
final SQLiteDatabase db=mOpenHelper.getWritableDatabase();
db.beginTransaction();
试一试{
ContentProviderResult[]results=super.applyBatch(操作);
db.setTransactionSuccessful();
返回结果;
}最后{
db.endTransaction();
}
}
为了正确起见:您想拥有一个URI并通过一次对ContentProvider的插入调用插入一篇文章及其所有标记吗?对吗
问题是,您需要在ContentValues对象中包含所有值。在数据库中进行规范化是有原因的。然而,这可能是可行的。对于标签,这应该很容易。只需对所有标记使用一个字符串。例如“android,ios,bada,wp7”,并在insert方法中解析这个字符串
您还可以使用命名加整数约定。只要有一个tag1,tag2,。。。tagX您可以从ContentProvider的insert方法中读取这些值
这两种方法都不优雅,但都能奏效
在这种情况下,bulkInsert或applyBatch在代码中没有位置。只有当您希望在一个事务中同时使用多个对ContentProvider的调用时,它们才会起作用
但我认为更好的解决方案确实是实际使用biegleux所描述的多个操作。因为您将要在多个表中插入正常的SQLiteDatabase。insert
helper函数将不起作用。但这是完全可以做到的一个性能和良好的方式
您需要从将要插入到您的ContentProvider中的用户的端点来查看这一点,即使它只是您自己。因此,首先为所有字段定义名称或键。由于您不会使用SQLiteDatabase.insert
,因此实际上不需要将它们命名为与数据库字段相同的名称。所有名称都不应重复。例如,如果两个不同表中的字段重叠,则在TableA
和TableB
中,可以将这些字段的名称定义为TableA.tag
和TableB.tag
。或者使用语义命名,以获得更具描述性且不冲突的名称
接下来,您需要使用SQLiteStatement
为此创建插入查询。确保在createInsert
中使用的名称与ContentProvider的调用者在ContentValues中用作键的名称相同。一篇文章有许多标记,因此我需要传递一个数组或一组标记。我看不出ContentValues是可能的。@Gal:要插入多个标记,一个hack-y方法是插入逗号分隔的字符串。这并不优雅,但它可以工作。因此,不公开子表的唯一方法是使用applyBatch
?您仍然需要定义插入子表的uri,这是访问ContentProvider的方式(如果您不允许查询子表,可以对子表抛出IllegalArgumentException for query()操作),对内容提供程序的访问是基于uri的,提供程序主要用于一个表,当涉及到表之间的关系时,它们有一定的限制,但是公开单独的uri以插入子表posted applyBatch()并没有错方法帮助您准备操作并在一个事务中执行操作使用内容提供程序而不是自己的数据库适配器实现是一种折衷方法使用ContentProvider