在Core Data中镜像远程数据库的最佳策略是什么?

时间:2011-04-22 10:37:01

标签: database web-services core-data

假设我在数据库中有两个表:费用和帐户。费用是我感兴趣的数据,该表具有Account的外键。这个数据库是远程的,通过Restful-esque命令访问,我想在iPhone上的Core Data数据存储中只镜像我的应用程序所需的数据。我正在使用的实际DB比这个例子大得多。 ~30个表和费用表有~7个FK。我正在与进行API设计的人密切合作,因此我可以根据需要修改我提出请求或返回数据的方式。

将此数据加载到Core Data的最佳策略是什么?

我的第一个想法是让费用请求带回FK的ID。

<expense>
    <date>1/1/2011</date>
    <cost>1.50</cost>
    <account_id>123</account_id>
</expense>

如果我的数据存储中已经有一个ID为“123”的帐户,这样可以正常工作。如果我不这样做,那么每次遇到我没有的ID时,我都要提出额外的网页请求......这将非常慢。我可以通过以特定顺序发出请求来解决这个问题,即在请求费用之前请求所有新帐户,以便我知道所有FK行都存在。一旦数据库开始达到中等复杂度,我觉得这会变得太麻烦。

我的第二个想法是让请求返回的数据跟随FK并从FK返回数据。

<expense>
    <date>1/1/2011</date>
    <cost>1.50</cost>
    <account>
        <id>123</id>
        <name>Bob's Big Boy</name>
        <address>1234 Main Street</address>
    </account>
</expense>

这看起来更好,并保证在需要时我将拥有所需的所有数据。如果我还没有帐户'123',我可以从该XML创建一个新的帐户对象。但是,我对这种方法的关注是,随着数据库复杂性的增加,这些XML文件可能会变得过大。 Expenses表有~7个外键,每个表都有多个FK。感觉就像对一个Expense的简单请求最终可能会返回大量数据。

其他人如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

我假设在任何给定时间您只想在本地应用程序中缓存部分服务器数据库,并且缓存的数据可能会随时间变化。

您可能希望使用“存根”实体来表示尚未实际下载的相关对象。您可以设置如下实体:

Expense{
  date:Date
  cost:Number 
  account<<-->AccountStub.expenses
}

AccountStub{
  id:Number
  expenses<-->>Expenses.account
}

Account:AccountStub{
  name:String
  address:String
}

AccountStub实体具有根据Expense表提供的信息在服务器DB中标识帐户所需的最低限度信息。它在完全成熟的Account对象的对象图中充当占位符(如果您愿意,可以将其视为一种类型的错误。)

由于Expenses与AccountStub有关系,而Account从AccountStub继承,您可以根据需要换掉AccountStub的帐户(反之亦然)。

您需要为AccountStub和Account提供自定义子类,以便AccountStub可以在实际需要该数据时触发帐户数据的下载和Account对象的创建。然后,新的Account对象应该在其所有关系中换掉AccountStub(这可能需要相当多的代码。)

要使用,您首先要获取Expense对象的数据并创建该对象。您将尝试使用Expense表数据提供的ID来获取AccountStub。将提取设置为包含子条目。如果存在具有该ID的AccountStub或Account对象,则会将Expense对象添加到该关系中。如果没有,则使用该ID创建AccountStub对象并将其添加到关系中。现在您有了一个基本对象图,显示了Expense对象与AccountStub对象的关系。要访问费用的帐户数据,您首先要检查相关帐户是存根还是完整帐户。如果是存根,则需要在之前加载完整的帐户数据。

这个系统的优点是你可以维护一个相当复杂的对象图,而不必在本地拥有所有数据。例如。你可以保持几种关系并走这些关系。例如,您可以像这样扩展您的模型:

AccountStub{
  id:Number
  expenses<-->>Expenses.account
  owner<<--AccountOwnerStub.accounts
}

AccountOwnerStub{
    id:Number
    accounts<-->>AccountStub.owner
}

AccountOwner{
    name:String
    address:String
    bill:Number
}

如果您想查找Expense对象的帐户所有者的名称,您只需使用account.owner.name遍历存根的关系,Account对象本身将只是一个存根。

如果您需要在本地节省空间,可以将对象还原为存根,而不会影响图表。

这需要一些工作,您必须密切关注存根,但它可以让您镜像复杂的外部数据库而无需保留所有数据。