考虑一个动物目录的iPhone应用程序。该应用程序应该允许用户为每只动物添加自定义信息 - 比如评级(1到5的等级),以及他们可以输入的关于动物的一些注释。但是,用户将无法修改动物数据本身。假设当应用程序更新时,(静态)目录部分应该很容易更改,但我们希望在更新之间保留(动态)自定义用户信息部分,这样用户就不会丢失任何他们的自定义信息。
我们可能想要使用Core Data来构建这个应用程序。我们还要说,我们已经有一个先前的流程来读取动物数据,以预先填充Core Data使用的支持(SQLite)存储。我们可以将此数据库文件嵌入到应用程序包本身中,因为它不会被修改。当用户下载应用程序的更新时,新版本将包含最新的(静态)动物目录数据库,因此我们不必担心它已过时。
但是,现在是棘手的部分:我们如何以合理的方式存储(动态)用户自定义数据?
我首先想到的是(动态)数据库应存储在应用程序的Documents目录中,因此应用程序更新不会破坏现有数据。我是对的吗?
我的第二个想法是,由于(动态)用户自定义数据数据库与(静态)动物目录不在同一个商店中,我们不能天真地在Rating和Notes实体之间建立关系(在一个数据库中) )和Animal实体(在另一个数据库中)。在这种情况下,我想象一个解决方案是在Rating / Notes实体中有一个“animalName”字符串属性,并在运行时匹配它。这是最好的方法吗,还是有办法在Core Data中“同步”两个不同的数据库?
答案 0 :(得分:2)
这基本上是我最终解决这个问题的方法。
虽然Amorya和MHarrison的答案是有效的,但他们有一个假设:一旦创建,不仅是表格,而且每个表格中的每一行都将是相同的。
问题在于,我使用现有数据(定期更新)预填充“Animals”数据库的过程每次都会创建一个新的数据库文件。换句话说,我不能依赖于在Core Data中创建(静态)Animal实体和(动态)Rating实体之间的关系,因为下次重新生成应用程序时该实体可能不存在。为什么不?因为我无法控制Core Data如何在幕后存储这种关系。由于它是一个SQLite后备存储,它很可能是使用具有外键关系的表。但是,当您重新生成数据库时,您无法假设每行获取密钥的值。如果我在列表中添加了狐猴,那么第二次狮子的主键可能会有所不同。
避免此问题的唯一方法是只需要预先填充数据库一次,然后在每次更新时手动更新行。但是,在我的情况下,这种过程实际上是不可能的。
那么,解决方案是什么?好吧,因为我不能依赖Core Data所做的外键关系,所以我必须自己编造。我所做的是在我的数据库生成过程中引入一个中间步骤:我不是采用我的原始数据(恰好是UTF-8文本,但实际上是MS Word文件),而是直接用Core Data创建SQLite数据库,我介绍了一个中介步骤:我将.txt转换为.xml。为何选择XML?好吧,不是因为它是一个银弹,而仅仅因为它是一种我可以很容易解析的数据格式。那么这个XML文件有什么不同呢?我为每个Animal生成的哈希值,使用MD5,我认为是唯一的。哈希值是多少?那么,现在我可以创建两个数据库:一个用于“静态”Animal数据(我已经有一个进程),另一个用于“动态”评级数据库,iPhone应用程序创建该数据库并且存在于应用程序的Documents目录中。对于每个评级,我通过保存Animal实体的哈希值来创建与Animal的伪关系。因此,每次用户在iPhone上显示Animal详细信息视图时,我都会查询“动态”数据库,以查找是否存在与Animal.md5Hash值匹配的Rating实体。
由于我正在保存这个中间XML数据文件,下次有更新时,我可以将它与我用来查看更改内容的最后一个XML文件区分开来。现在,如果一个动物的名字被改变了 - 让我们说一个拼写错误被纠正了 - 我还原那个动物的哈希值。这意味着即使更改了动物名称,我仍然可以在“动态”数据库中找到匹配的等级(如果存在)。
此解决方案还有另一个好的副作用:我不需要处理任何迁移问题。随应用程序提供的“静态”Animal数据库可以作为应用程序资源嵌入。它可以改变它想要的一切。如果我修改其数据模型以添加更多实体,那么“动态”评级数据库可能需要在某些时候进行迁移,但实际上这两个数据模型保持完全独立。
答案 1 :(得分:1)
我这样做的方式是:将静态内容的数据库作为应用程序包的一部分。在应用程序启动时,检查Documents中是否有数据库文件。如果没有,请将应用程序包中的一个复制到Documents。然后从Documents打开数据库:这是您从中读取和编辑的唯一数据库。
升级时,新的静态内容需要与用户的可编辑数据库合并。每个静态项(在您的情况下为Animal)都有一个名为factoryID的字段,该字段是唯一标识符。在更新后的第一次启动时,从应用程序包中加载数据库,并遍历每个Animal。对于每个,在工作数据库中找到适当的记录,并根据需要更新任何字段。
可能有一个更快的解决方案,但由于升级过程不会经常发生,因此所花费的时间不应太成问题。
答案 2 :(得分:1)
将您的SQLite数据库存储在Documents目录(NSDocumentDirectory)中肯定是要走的路。 通常,您应该尽可能避免修改或删除SQL表的应用程序更改(添加正常)。但是,如果您必须在更新中进行更改,就像Amorya所说的那样 - 打开旧数据库,将您需要的任何内容导入到新数据库中,并删除旧数据库。
由于听起来您想要一个无法修改的“动物”表的静态数据库,因此只需将这个表替换为升级就不是问题 - 只要条目的ID不是更改。存储有关动物的用户数据的方式是为用户创建的每个条目创建与动物ID的外键的关系。这是升级更改时需要迁移的内容。