Coredata在节中提取和分组对象

时间:2011-08-15 21:55:28

标签: ios core-data nsfetchedresultscontroller nspredicate

我正在处理一个非常复杂的对象模型,并且在将部分内容分解为多个部分以显示在tableview中时遇到了一些麻烦。

我需要将Meeting托管对象分组到几个不同的“口袋”中,例如项目,客户端和其他一些。出于几个原因,我决定将这些实现为可以与会议实体关联的标签。

所以我创建了一个新的Tag实体,它有一个类型和一个值,并建立了两者之间的关系:

Meeting <<-->> Tag

如果我想将会议与项目关联,我创建一个名为'project'的标签,并将值'Project Name',然后通过关系将其添加到会议实体。

我最初想过使用NSFetchedResultsController,但是我遇到了各种各样的问题,而这些问题我并不是很理解。

例如,这个获取(我省略了不必要的位):

NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:[Meeting entityName] inManagedObjectContext:moc];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"tags.name contains[] 'client'"];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"title" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
[fetch setEntity:entity];
[fetch setPredicate:predicate];
[fetch setSortDescriptors:sortDescriptors];
NSFetchedResultsController *frc = [[NSFetchedResultsController alloc] initWithFetchRequest:fetch 
                                                                      managedObjectContext:moc 
                                                                        sectionNameKeyPath:@"self.tags.value" 
                                                                                 cacheName:nil];

在这种特殊情况下,fetch确实有效,但不知怎的,我得到了意想不到的结果,不仅Tags带有值client,还有值project ???

如果我将谓词更改为tags.name == 'project',我会收到例外:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'to-many key not allowed here'

我可能在这里遗漏了一些基本的东西,不可否认,我对谓词没有很多经验,但Apple关于这个主题的文档还有很多不足之处。

作为一个侧面问题和我不明白的问题,为什么我必须将self添加到self.tags.value中的sectionNameKeyPath?它有什么作用??在这种情况下,如果我不添加它,我也会抛出异常:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid to many relationship in setPropertiesToFetch: (tags.value)

最后,在这种情况下,使用fetched results controller的替代方法是什么?它是一堆获取请求,我首先获取Tag的每个实例name == 'project'并迭代数组以拉出与之关联的Meeting对象?这看起来非常低效,但我现在只能想到所以如果你有任何其他的想法,我很有兴趣听到它们。

非常感谢你的时间,

罗格

2 个答案:

答案 0 :(得分:3)

问题是Meeting有多个tags,因此您需要使用汇总操作:

NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:[Meeting entityName] inManagedObjectContext:moc];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ANY tags.name contains[cd] 'client'"];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"title" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
[fetch setEntity:entity];
[fetch setPredicate:predicate];
[fetch setSortDescriptors:sortDescriptors];
NSFetchedResultsController *frc = [[NSFetchedResultsController alloc] initWithFetchRequest:fetch 
managedObjectContext:moc 
sectionNameKeyPath:@"clientName"
cacheName:nil];

即。向我提供Meeting ANYtags clientclientName类型clientName对象的列表,并按- (NSString *)clientName { [self willAccessValueForKey:@"clientName"]; // Set clientName to the value of the first tag with name 'client' NSString* clientName = @"..."; [self didAccessValueForKey:@"clientName"]; return clientName; } 对其进行分组。要使NSManagedObject密钥路径起作用,您需要实现瞬态属性:

clientName

如果你的NSManagedObject个子类的数量需要{{1}}属性,你可以在一个公共的抽象{{1}}子类中实现它,并使你的具体子类继承它。

答案 1 :(得分:1)

“Apple关于[NSPredicate]的文档还有很多不足之处” - 完全同意!

tags.name无效,因为标签是一个集合,没有对象,有(比方说)其中三个

我认为你想要像"tags contains %@", projectTag这样的东西,但我不确定语法。可能是"%@ IN %@", projectTag, thing.tags