Sqlite 如何在使用一个ManagedObjectContext和PersistentStoreCoordinator与两个存储时保存数据

Sqlite 如何在使用一个ManagedObjectContext和PersistentStoreCoordinator与两个存储时保存数据,sqlite,core-data,ios7,persistent-storage,managedobjectcontext,Sqlite,Core Data,Ios7,Persistent Storage,Managedobjectcontext,问题陈述 当试图将记录保存到读/写存储时,我的iPhone应用程序崩溃。读/写存储是分配给同一PersistentStoreCoordinator的两个SQLite存储之一。保存记录时一个明显的问题是PersistentStoreCoordinator不知道在哪个存储中保存数据(只是因为我不知道如何实现这一点) 首先,我将提供大局图,以确保我的方法是合理的。然后我将提供实现细节 背景 这是一个简化的示例,代表了我正在开发的实际应用程序的关键方面 种子数据 用户输入场景 当前实施情况 核心数

问题陈述

当试图将记录保存到读/写存储时,我的iPhone应用程序崩溃。读/写存储是分配给同一PersistentStoreCoordinator的两个SQLite存储之一。保存记录时一个明显的问题是PersistentStoreCoordinator不知道在哪个存储中保存数据(只是因为我不知道如何实现这一点)

首先,我将提供大局图,以确保我的方法是合理的。然后我将提供实现细节

背景

这是一个简化的示例,代表了我正在开发的实际应用程序的关键方面

种子数据

用户输入场景

当前实施情况

核心数据实现

数据存储和检索

当然,当用户查看选择列表以选择属性时,不应该有证据表明这些选择来自两个不同的商店

持久存储协调器设置

重要目标

请记住以下几点:

  • 如果可能的话,我更愿意进行种子数据更新,而不必在幕后管理数据版本(即,仅提供应用程序更新,以新的或更改的种子数据记录,并以某种方式处理删除)或者在代码中实现版本检查功能,以处理用户从版本n升级到n+5的情况
  • 用户数据和种子数据之间不应包含任何重复记录,并使用相同的ManagedObjectModel。因此,从数据和模型的角度来看,不需要合并两个存储或将一个存储迁移到另一个存储
  • 研究

    在这种情况下,, , 这两个存储被合并,然后获取所有记录,剔除重复项,并保存上下文。我希望不必合并然后检查数千条记录的重复项。(参见上述重要目标#2。)

    在这种情况下,, , 某些实体是只读的,而其他实体是读/写的。在我的应用程序中,种子数据存储中的所有实体都是只读的,而用户数据存储中的相同实体都是读/写的。所以我认为迁移是不适用的。(参见上述重要目标#2。)

    在Apple的“Persistent Store Coordinator”下,图4“Advanced persistence stack”显示了一个使用两个存储的核心数据实现,但同样,每个存储都配置了独立的对象。在我的应用程序中,每个对象都出现在每个商店中

    这里提出的解决方案,, , 相对于拥有两个没有关系的存储,不同存储中的对象之间似乎有关联,但没有提供与我实现的内容相比较的详细信息

    我已经阅读了的前三章,但是他没有使用两个不需要迁移的商店。然而,第3章提供了一个非常清晰的版本控制示例。(正是这种复杂性让我实现了上面的重要目标#1。)

    此解决方案建议使用ManagedObjectModel的多个配置,但每个实体都分配给一个且仅分配给一个配置。我不知道如何,甚至是否,这个解决方案可以外推到我的情况


    也许这里提出的解决方案接近我的需要。不幸的是,只有请求被处理。在NSManagedObjectContext类中,我没有看到类似于NSFetchRequest方法setAffectedStores的用于保存的方法。

    对于使用一个上下文/协调器和两个存储保存数据的核心问题,您需要的方法是:

  • 通过
    addPersistentStore
    添加用户可编辑存储时,保存对返回的
    NSPersistentStore
    对象的引用
  • 创建要保存在用户可编辑存储中的新对象时,请执行以下操作:

    NSManagedObject *newObject = [NSEntityDescription insertNewObjectForEntityForName:@"Vehicle" inManagedObjectContext:self.managedObjectContext];
    [self.managedObjectContext assignObject:newObject toPersistentStore:userEditableStore];
    
    这里的关键是在保存更改之前显式调用
    assignObject:toPersistentStore:

  • 有关问题:

    如果可能的话,我更愿意进行种子数据更新,而不必在幕后管理数据版本

    如果您将不可编辑的存储区保留在应用程序包中(即,您没有将文件复制到其他地方),您可以将新版本的数据与新版本的应用程序一起包含。您将始终使用应用程序包中的任何版本,因此您将获得最新数据

    如果您最终将数据从种子存储复制到用户存储,请确保每个条目在添加时都包含应用程序(或种子存储)版本号。这样就很容易避免重复

    用户数据和种子数据之间不应包含任何重复记录,并使用相同的ManagedObjectModel。因此,从数据和模型的角度来看,不需要合并两个存储或将一个存储迁移到另一个存储

    如果不同存储中的对象之间没有任何关系,则不需要将数据从一个拷贝到另一个,因为核心数据中不允许这样做。如果您需要关系(听起来像是这样),那么查看获取的属性。它们看起来很像实体类型上的属性或关系,但在内部它们从持久存储中查找值。有了多个持久性存储文件,这使得不同存储中的对象之间的关系几乎相似,但并不完全相似。

    多亏了Mic的参考,Mic提出了一种托管对象模型体系结构,我能够在坚持目标的同时解决问题。解决方案的关键是利用抽象实体作为用户和种子实体的父实体

    使用此体系结构,可以创建分配给不同存储的两种配置: 1) 美国
    NSManagedObject *newObject = [NSEntityDescription insertNewObjectForEntityForName:@"Vehicle" inManagedObjectContext:self.managedObjectContext];
    [self.managedObjectContext assignObject:newObject toPersistentStore:userEditableStore];