Android内容提供程序SQLite连接表

时间:2015-12-12 13:48:56

标签: android database sqlite android-contentprovider junction-table

我正在实现一个内容提供程序,它由相当复杂的SQLite数据库架构支持。数据库有一些联结表,我不确定它们是否应该对Content Provider的用户可见。

父表通过Contract公开,每个表都有自己的内容URI等。现在,当通过ContentResolver#applyBatch()方法插入数据时,我为每个表的内容创建ContentProviderOperation URI。到目前为止一切都很清楚。但我的问题是,如何填充联结表,因为它们没有自己的内容URI?

为了说明这一点,这是一个例子。我有2个“父”表,MoviesActors。它们之间的关系是多对多的,因此我有一个名为MoviesActors的联结表。

要在一个批次中插入,我会执行以下操作:

List<ContentProviderOperation> operations = new ArrayList<>;
// movie
operations.add(ContentProviderOperation.newInsert(Contract.Movie.ContentUri).withValue("movie_id", "23asd2kwe0231123sa").build());
// actor
operations.add(ContentProviderOperation.newInsert(Contract.Actor.ContentUri).withValue("actor_id", "89asd02kjlwe081231a").build());
getContentResolver().applyBatch(authority, operations);

应插入联结表MoviesActors,其中包含movie_idactor_id的行。在这种情况下如何处理联结表?

我唯一想到的就是扩展Contract以使内容URI指向联结表并添加另一个ContentProviderOperation,否则,你如何沟通movie_id和{{1到actor_id

我宁愿不将联结表暴露给ContentProvider的用户,但我可能在这里错了......也许这就是在Android上应该怎么做?

我已经搜索了这个主题好几天了,但还没有找到答案。 任何帮助将不胜感激。

加分问题:

是否有必要通过合同公开每一张桌子?例如,当具有一对多关系的子表时。我特别指的是插入/更新/删除,因为我知道查询我可以简单地进行连接,但也许我在这里也错了。

非常感谢!

注意:我对第三方库解决方案不感兴趣。

1 个答案:

答案 0 :(得分:1)

我认为你是从错误的一端解决问题的。您正在尝试设计一个与您的数据库结构相匹配的接口,但接口应该是第一个。

首先,界面应满足ContentProvider客户端的所有要求。如果您的ContentProvider客户端需要访问联结表,您必须公开它(以某种方式,见下文),否则您不必这样做。一个好的界面隐藏了实际的实现细节,因此ContentProvider客户端不需要关心ContentProvider是由SQLite数据库,一堆内存映射还是Web服务支持。

此外,您不应将ContentProvider视为数据库的接口,而将Contract视为数据库架构。 ContentProvider比这更通用,更强大。主要区别在于ContentProviders由URI解决,而在SQL中,您只有表名。与表名相反,URI具有结构。 URI具有标识要对其进行操作的对象(或对象目录)的路径。您还可以将查询参数添加到URI以修改操作的行为。在这方面,ContentProvider可以像RESTful服务一样设计。

请参阅下文,了解简单电影数据库合约的具体(但不完整)示例。这基本上就是设计RESTful网络服务的方式,除了一件事:就像你的代码一样, movie-id actor- id 由来电者提供。真正的RESTful服务会自动创建和分配这些服务并将它们返回给调用者。 ContentProvider在插入新对象时只能返回long个ID。

插入新电影

在/ movies /

插入

值:{"movie_id": <movie-id>, "title": <movie-title>, "year": ...}

插入新演员

在/ actors /

插入

值:{"actor_id": <actor-id>, "name": <actor-name>, "gender": ...}

将现有演员添加到电影

在/ movies / movie-id / actors /

插入

值:{"actor_id": <actor-id>}

将现有影片添加到演员:

在/ actors / actor-id / movies /

插入

值:{"movie_id": <movie-id>}

可选:直接向电影添加新演员:

在/ movies / movie-id / actors /

插入

值:{"actor_id": <actor-id>, "name": <actor-name>, "gender": ... }

如果不存在具有给定id的actor,则此操作将创建新actor并在一个步骤中将其链接到影片。如果具有此ID的actor已经存在,则将抛出异常。 反过来也可以这样做,为演员添加一部新电影。

从电影中删除演员

movie-id / actors / actor-id

删除 / actors / actors-id / movies / movie-id

获取所有电影

/ movies /

上的

查询

获取特定电影

/ movies / movie-id

查询

让所有演员在特定电影中播放

/ movies / movie-id / actors /

上的

查询

获取特定演员在

中播放的所有电影

查询 / actors / actor-id / movies /

可选的查询选择语句可用于过滤结果。要获取特定演员过去10年的电影,您可以将选择movies_year>=2005添加到上一个查询中。

通过使用这样的合同,您不会公开联结表,而是为数据库提供类似REST的界面。

ContentProvider的工作是将这些操作映射到数据库或任何其他后端。