7

我在 SO 中进行了搜索,但没有找到任何建议来提高在处理关系时删除 Core Data 中的托管对象的性能。

场景非常简单。在此处输入图像描述

如您所见,存在三个不同的实体。每个实体都与下一个实体级联。例如,FirstLevel有一个名为secondLevelsto的关系SecondLevel。从FirstLevelto的删除规则SecondLevelCascade而从SecondLevelto的删除规则FirstLevelNullifySecondLevel在和之间应用相同的规则ThirdLevel

当我想删除整个图表时,我执行如下方法:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"FirstLevel" inManagedObjectContext:context];
[fetchRequest setEntity:entity];

NSError *error = nil;
NSArray *items = [context executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];    

// delete roots object and let Core Data to do the rest...
for (NSManagedObject *managedObject in items) {
    [context deleteObject:managedObject];
}

利用级联规则,图被删除。这对少数对象快速有效,但会降低许多对象的性能。另外,我认为(但我不太确定)这种类型的删除对磁盘执行了很多往返,我错了吗?

所以,我的问题如下:如何在不利用级联规则和提高性能的情况下删除图形,但同时保持图形一致性?

先感谢您。

编辑

我无法删除整个文件,因为我的模型中有其他实体。

编辑 2

我发布的代码包装在子类的main方法中NSOperation。此解决方案允许在后台执行删除阶段。由于我利用了级联规则,因此删除是以半自动方式执行的。FirstLevel我只通过发布代码中的 for 循环删除根对象,即项目。这样Core Data就为我做剩下的事情了。我想知道的是:是否可以绕过半自动删除操作并手动执行而不丢失图形一致性?

4

2 回答 2

5

对于遍历和删除数据库中的对象所花费的时间,您无能为力。但是,您可以在后台执行此操作,这样 UI 就不会被阻止。

例如,类似(代码假定为 ARC - 并且只是输入 - 未编译)......

- (void)deleteAllLevelsInMOC:(NSManagedObjectContext*)moc
{
    // Create a context with a private queue, so access happens on a separate thread.
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    // Insert this context into the current context hierarchy
    context.parentContext = context;
    // Execute the block on the queue of the context
    context.performBlock:^{
            NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"FirstLevel"];
            // This will not load any properties - just object id
            fetchRequest.includesPropertyValues = NO;
            // Iterate over all first-level objects, deleting each one
            [[context executeFetchRequest:fetchRequest error:0] 
                enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
                [context deleteObject:obj];
            }];
            // Push the changes out of the context
            [context save:0];
    }];
}

请注意,您可以将 RootLevel 对象添加到您的数据模型中,并赋予它与第一级对象的一对多关系。然后,(只要你只有一个根对象)你所要做的就是删除那个根对象,它会删除 CoreData 中的所有其他内容。如果您有很多 FirstLevel 对象,那将是要走的路。

或者,您可以将“新”上下文直接连接到持久存储,进行更改,并让其他上下文监视更改通知。

顺便说一句,如果您使用 UIManagedDocument,您可以免费获得这种背景,因为已经有一个父上下文在其自己的队列上运行,并且对主上下文的所有更改都传递给父上下文以实际执行数据库工作。

编辑

您可以手动执行此操作,但您必须关闭级联规则。我发现我希望 CoreData 为我做尽可能多的事情。它减少了我的错误余地。

如果您已经在后台线程中删除,那么您如何看待性能问题?您必须在删除期间进行查询......这意味着您正在使用完成所有工作的 MOC。

你应该从 UIManagedDocument 中吸取教训。你应该有一个在私有队列上运行的 MOC。它完成了所有真正的工作。您有一个子 MOC,它只是将工作传递给该工作队列。

如果您实际上是在查询不在您要删除的图形中的对象,它们可能会被持久存储协调器的序列化属性挂起。如果是这种情况,您应该考虑单独的协调员,或者只有两个商店。

这样,您可以根据需要删除图表中的对象,同时仍然响应对其他对象的请求。

于 2012-04-19T13:48:18.580 回答
1

我通常按​​照此处所述打开 Core Data SQL 跟踪:http -com.apple.CoreData.SQLDebug 1: //useyourloaf.com/blog/2010/3/11/debugging-core-data-on-the-iphone.html 这有助于检查 Core Data 所做的事情期待它在幕后做。

您是否确保 [moc save:...] 需要这么长时间,而不是实际的 fetchrequest 来获取要删除的对象?如果是这种情况,您可以批量获取(然后删除)那些第一级对象。

于 2012-04-20T15:26:34.237 回答