使用具有两个存储的一个ManagedObjectContext和PersistentStoreCoordinator时如何保存数据

时间:2014-05-14 21:46:19

标签: sqlite core-data ios7 persistent-storage managedobjectcontext

问题陈述

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

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

背景

这是一个简化示例,代表了我正在处理的实际应用的关键方面。

Managed Object Model

种子数据

Seed Data

用户输入方案

User Input Scenario

当前实施

核心数据实施

Core Data Implementation

数据存储和检索

Data Storage and Retrieval

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

持久性商店协调员设置

- (NSPersistentStoreCoordinator*)persistentStoreCoordinator {
   if (_persistentStoreCoordinator == nil) {
       NSArray *bundles = @[[NSBundle bundleForClass:[self class]]];
       _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[NSManagedObjectModel mergedModelFromBundles:bundles]];

       NSError *error;
       //--------------------------------------------------
       // Set options for the USER DATA Persistent Store.
       NSDictionary *options = @{NSMigratePersistentStoresAutomaticallyOption : @YES,
                                       NSInferMappingModelAutomaticallyOption : @YES};
       //--------------------------------------------------
       // Add the USER DATA Store to the Persistent Store Coordinator.
       NSPersistentStore *persistentStore = [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
                                                                                   configuration:nil
                                                                                             URL:self.persistentStorePathForUserData
                                                                                         options:options
                                                                                           error:&error];
       //--------------------------------------------------
       // Set options for the SEED DATA Persistent Store.
       options = @{NSMigratePersistentStoresAutomaticallyOption : @YES,
                         NSInferMappingModelAutomaticallyOption : @YES,
                                NSReadOnlyPersistentStoreOption : @YES};
       //--------------------------------------------------
       // Add the SEED DATA Store to the Persistent Store Coordinator.
       persistentStore = [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
                                                                configuration:nil
                                                                          URL:self.persistentStorePathForSeedData
                                                                      options:options
                                                                        error:&error];
   }
   return _persistentStoreCoordinator;
}

重要目标

请记住以下内容:

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

    在这种情况下, Save objects from multiple stores to single persistent store, 合并了两个商店,然后获取所有记录,剔除重复项并保存上下文。我希望不必合并,然后检查成千上万的记录重复。 (参见上面的重要目标#2。)

    在这种情况下, What is an efficient way to Merge two iOS Core Data Persistent Stores?, 某些实体是只读的,而其他实体是读/写的。在我的应用程序中,种子数据存储中的所有实体都是只读的,并且用户数据存储中的相同实体是可读/写的。所以我不认为迁移是适用的。 (参见上面的重要目标#2。)

    在Apple的,Core Data Programming Guide下的“Persistent Store Coordinator”下,图4“高级持久性堆栈”显示了使用两个商店的Core Data实现,但同样,每个商店都配置了独立且不同的对象。在我的应用中,每个对象都出现在每个商店中。

    这里提出的解决方案, Combining Two SQLite Stores Into One, 相对于在不同商店中没有关系的两个商店似乎相关,但没有提供与我实施的内容相比较的细节。

    我已经阅读了Core Data (2nd Edition), by Marcus Zarra的前三章,但他没有使用两个不需要迁移的商店。但是,第3章确实提供了一个非常明确的版本控制示例。 (这很复杂导致我上面的重要目标#1。)

    此解决方案Which persistent store is used by default in core data in iPhone建议使用ManagedObjectModel的多个配置,但每个实体都分配给一个且仅一个配置。我不确定这个解决方案是如何,甚至可以根据我的情况推断的。

    也许这里提出的解决方案NSPersistentStoreCoordinator with two types of persistent stores?接近我的需要。不幸的是,只解决了请求。我没有在类NSManagedObjectContext中看到类似于NSFetchRequest方法setAffectedStores的方法进行保存。

2 个答案:

答案 0 :(得分:2)

感谢Ray Wenderlich推荐到Mic Pringle,Mic提出了一个托管对象模型架构,通过该架构,我能够在坚持目标的同时解决问题。解决方案的关键是将抽象实体用作用户和种子实体的父实体。

Managed Object Model

使用此体系结构,可以创建分配给不同商店的两个配置: 1)UserData - 位于用户文档目录中的r / w商店。

UserData Configuration

2)SeedData -r仅存储在App Bundle中的商店。

SeedData Configuration

缺点是必须为种子数据实体维护记录ID(因为配置之间不允许关系),但是巨大的好处是可以对种子数据进行更改或添加而不影响种子数据用户的条目并且不必采用本问题原始帖子的研究部分中讨论的任何繁琐的解决方案。

答案 1 :(得分:0)

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

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

    NSManagedObject *newObject = [NSEntityDescription insertNewObjectForEntityForName:@"Vehicle" inManagedObjectContext:self.managedObjectContext];
    [self.managedObjectContext assignObject:newObject toPersistentStore:userEditableStore];
    

    此处的关键是在保存更改之前明确调用assignObject:toPersistentStore:

  3. 相关问题:

      

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

    如果您将不可编辑的商店留在应用包中(即您不会将文件复制到其他地方),您可以使用新版本的应用包含新版本的数据。您将始终使用应用包中的任何版本,因此您将获得最新数据。

    如果执行最终将数据从种子存储区复制到用户存储区,请确保每个条目在添加时包含应用程序(或种子存储区)版本号。这样可以轻松避免重复。

      

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

    您不需要将数据从一个复制到另一个如果您不同商店中的对象之间没有任何关系 - 因为那不是核心数据允许。如果您需要关系(听起来像你这样做),那么请查看获取的属性。它们看起来很像实体类型的属性或关系,但在内部它们从持久性存储中查找值。对于多个持久性存储文件,这允许某些东西几乎但不太像是不同商店中的对象之间的关系。