setIncludesSubentities:在多个持久性存储中的实体中,NSFetchRequest被破坏

时间:2010-05-03 20:49:42

标签: cocoa core-data nsfetchedresultscontroller nsfetchrequest

现有技术并未完全解决这个问题: Core Data Migration error message "'Model does not contain configuration 'XYZ'.'"

我已将其缩小到特定问题。但是,设置需要一分钟;请耐心等待。

问题的关键在于,持久存储协调器(显然)无法保留对象图的一部分,当托管对象存储在不同文件中时,托管对象被标记为另一个子实体。这就是......

1)我有2个xcdatamodel文件,每个文件包含一个实体。在运行时,当构造托管对象模型时,我使用setSubentities:手动将一个实体定义为另一个实体的子实体。这是因为尚不支持在编辑器中定义多个文件的子实体。然后我使用modelByMergingModels返回完整的模型。

//Works! 
[mainEntity setSubentities:canvasEntities];
NSLog(@"confirm %@ is super for %@", [[[canvasEntities lastObject] superentity] name], [[canvasEntities lastObject] name]);
//Output: "confirm Note is super for Browser"

2)我修改了persistentStoreCoordinator方法,以便为每个实体设置不同的存储。从技术上讲,它使用配置,每个实体只定义一个配置。

//Also works!
for ( NSString *configName in [[HACanvasPluginManager shared].registeredCanvasTypes valueForKey:@"viewControllerClassName"] ) {
storeUrl = [NSURL fileURLWithPath:[[self applicationDocumentsDirectory] stringByAppendingPathComponent:[configName stringByAppendingPathExtension:@"sqlite"]]];
//NSLog(@"entities for configuration '%@': %@", configName, [[[self managedObjectModel] entitiesForConfiguration:configName] valueForKey:@"name"]);
//Output: "entities for configuration 'HATextCanvasController': (Note)"
//Output: "entities for configuration 'HAWebCanvasController': (Browser)"
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:configName URL:storeUrl options:options error:&error])
//etc

3)我为父实体设置了fetchRequest,使用setIncludesSubentities:和setAffectedStores:只是为了确保我们同时覆盖1)和2)。当插入任一实体的对象时,它们都被添加到上下文中,它们都被fetchedResultsController提取并按预期显示在tableView中。

// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
[fetchRequest setIncludesSubentities:YES]; //NECESSARY to fetch all canvas types
[fetchRequest setSortDescriptors:sortDescriptors];
[fetchRequest setFetchBatchSize:20]; // Set the batch size to a suitable number.
[fetchRequest setAffectedStores:[[managedObjectContext persistentStoreCoordinator] persistentStores]];
[fetchRequest setReturnsObjectsAsFaults:NO];

这是它开始行为不端的方式:在关闭并重新启动应用程序后,仅提取父母实体。

如果我使用setEntity:将请求的实体更改为'Note'的实体,则会获取所有注释。如果我将其更改为“浏览器”的实体,则会获取所有浏览器。让我重申,在首次将对象插入上下文的运行期间,它将出现在列表中。只有在保存和重新启动之后,获取请求才能遍历层次结构。

因此,我只能得出结论,继承的存储就是问题所在。让我们回顾一下原因:

    - 可以创建,插入上下文和查看两个实体,因此模型正在运行
    - 可以使用单个请求获取两个实体,因此继承正在运行
    - 我可以确认文件是分开存储的,对象是否进入相应的商店,因此保存工作
    - 使用任一实体集为该请求启动应用程序,因此从商店检索工作
    - 这也意味着遍历请求的不同商店正在运行
    - 通过使用单个商店而不是多个商店,问题完全消失,因此创建,存储,提取,查看等工作正常。

这只留下了一个罪魁祸首(我的想法):我使用setSubentities设置的继承:仅对会话期间创建的对象有效。

正在存储剥离继承信息的对象/实体,或者以编程方式定义的实体继承仅适用于新实例或两者。这些都是不可接受的。无论是一个错误还是我的方式,远离当然。

我已经在这两天一直在这里;非常感谢任何见解。目前的解决方法 - 只使用一个商店 - 完全有效,除非我从应用程序中删除其中一个模型等不会出现面向未来。这也令人难以置信,因为我无法理解为什么你将所有这些基础设施用于存储在多个存储中,并且如果按照核心定义(setSubentities :)不起作用,则在获取请求中设置受影响的存储。

2 个答案:

答案 0 :(得分:4)

不幸的是答案很简单。不支持跨物理上不同的文件和/或模型的多样性。在底层数据结构中,Core Data将采用所有子实体并将它们展平为单个表。因此,如果你有一个Parent,ChildA,ChildB和ChildC,每个都有4个属性,那么你最终会得到一个包含16列的表。

这就是为什么不以您尝试的方式支持子实体的原因。每个模型本身都是一个孤岛,并且最多只能对其他模型中的对象进行弱引用。

更新

如上所述,这是“设计不支持”的问题。由于它在底层数据结构中的持久性,因此不支持您尝试执行的操作。创建子实体不是首先要做的事情,因为它会使数据模型变得扁平化。

实体继承等于对象继承。您的对象可以以任何方式,形状或形式继承。实体继承应该是非常罕见的,并且有一个非常背后的理由。

解决父子关系问题是使用实体继承的少数几个原因之一。

试图避免重复列是一个很好的理由。

由于您不能跨模型建立父/子关系(并且即使它们被合并到NSManagedObjectModel的一个实例中,您确实有多个模型),因此不太可能是在不能通过类似解决方案解决的模型中进行实体继承的原因。

答案 1 :(得分:0)

@SG

你问:

  

为什么所有这些钩子都可以在多个模型中读取,并保存到多个持久存储...

您可以拥有多个模型并将它们保存到不同的持久性存储中,因为您希望处理xcdatamodel的不同部分,例如:在重新排序EntityB的大量managedObject时,编辑EntityA的属性,从而影响与EntityB的关系。

您还可以在读取新对象时在另一个线程中执行更好的I / O流式传输,完成此工作后,您可以将它们与模型的现有数据“合并”。