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

Anr*_*pps 5 sqlite core-data persistent-storage managedobjectcontext ios7

问题陈述

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

首先,我将提供总体情况,以确保我的方法是正确的。然后我将提供实施细节。

背景

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

管理对象模型

种子数据

种子数据

用户输入场景

用户输入场景

目前的实施情况

核心数据实施

核心数据实施

数据存储和检索

数据存储和检索

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

持久存储协调器设置

- (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;
}
Run Code Online (Sandbox Code Playgroud)

重要目标

请记住以下几点:

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

研究

在这种情况下, 将多个存储中的对象保存到单个持久存储中,两个存储被合并,然后获取所有记录,剔除重复项,并保存上下文。我希望不必合并然后检查数千条记录是否有重复项。(参见上面的重要目标#2。)

在这种情况下, 合并两个 iOS 核心数据持久存储的有效方法是什么?,某些实体是只读的,而其他实体是读/写的。在我的应用程序中,种子数据存储中的所有实体都是只读的,用户数据存储中的相同实体都是读/写的。所以我认为移民不适用。(参见上面的重要目标#2。)

在 Apple 的Core Data 编程指南中的“持久性存储协调器”下,图 4“高级持久性堆栈”显示了使用两个 Store 的 Core Data 实现,但同样,每个 Store 都配置有单独且不同的对象。在我的应用程序中,每个对象都出现在每个商店中。

这里提出的解决方案, 将两个 SQLite 存储合并为一个,相对于拥有两个存储而不同存储中的对象之间没有关系似乎是相关的,但没有提供任何细节来与我所实现的进行比较。

我已经阅读了Marcus Zarra 所著的《Core Data》(第二版)的前三章,但他并没有开始使用两个不需要迁移的存储。然而,第 3 章确实提供了一个非常清晰的版本控制示例。(它的复杂性让我实现了上面的重要目标#1。)

这一解决方案(iPhone 中的核心数据默认使用 Which persistence store)建议使用 ManagedObjectModel 的多种配置,但每个实体都分配给一个且仅一个配置。我不确定如何或者是否可以将此解决方案推断到我的情况。

也许这里提出的解决方案是具有两种类型的持久存储的 NSPercientStoreCoordinator?,接近我所需要的。不幸的是,仅满足请求。我在 NSManagedObjectContext 类中没有看到类似于 NSFetchRequest 方法 setAffectedStores 的方法用于保存。

Anr*_*pps 2

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

管理对象模型

使用此架构,可以创建两个分配给单独存储的配置: 1) UserData - 位于用户文档目录中的读/写存储。

用户数据配置

2) SeedData - 仅存储在 App Bundle 中。

种子数据配置

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