1

我昨天问了一个问题,我真的应该从一个更简单的例子开始。将我的问题提炼为基础知识后,我设法使用现有的 SO 问题和答案解决了我的问题。

我在这里总结我的问题(并提供我自己的解决方案),因为我认为没有任何帖子足够清楚地解释这一点。作为 Core Data 的新手并努力摆脱 SQL 概念,我欢迎就我的解决方案的适用性以及是否有更好的问题建模方法提供反馈。

问题

给定以下对象模型,它具有三个实体 A、B 和 C,每个实体由一对多关系链接:

模型

如何识别具有具有特定属性的孙C实体的父A实体?例如,使用这些示例实体及其关系:

例子

我怎样才能找到我们的哪个实体A有带有标签的子实体C:是?

解决方案

我已经能够通过使用SUBQUERY关键字来实现这一点NSPredicate。这是对我有用的代码片段(假设您已经设置了托管对象上下文等):

NSError *error = nil;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"EntityA" inManagedObjectContext:context];   
[fetchRequest setEntity:entity];
NSPredicate *predicateTemplate = [NSPredicate predicateWithFormat:@"(0 != SUBQUERY(child, $a, (0 != SUBQUERY($a.child, $child, $child.tag == %@).@count)).@count)", @"YES"]; 
[fetchRequest setPredicate:predicateTemplate];
NSArray *test = [context executeFetchRequest:fetchRequest error:&error];

将所有重要的 NSPredicate 字符串分成几行:

(0 != SUBQUERY(child, 
               $a, 
               (0 != SUBQUERY($a.child,
                              $child, 
                              $child.tag == %@).@count)
               ).@count
)

重要的部分是我们选择EntityA要从中工作的对象,然后在嵌套子查询child中处理实体的关系。我希望这可以重复几个深度。放在一起不是最直观的东西......但它确实有效。欢迎评论。

4

2 回答 2

2

如果您遵循核心数据指南并建立了互惠关系,您可以尝试自下而上进行搜索。

获取传递您所需谓词的实体 C 对象,然后通过向上父级获取实体 A 对象。不需要嵌套子查询。

编辑添加

您可以从关系中获取 C 的父级(它是 B 的对象)parent。从那里您可以从关系中获取父级(它是 A 的对象)parent

它在您的核心数据模型图中。

于 2012-10-05T18:27:51.297 回答
2

我以前从未尝试过使用子查询,这很酷,很高兴看到它的示例。您实际上应该添加解决方案作为问题的答案!

我可能会按照 Abizern 的建议去做,因为这是一个类似树的层次结构,并且使用一对一的关系更容易遍历树。

在代码中,这看起来像:

NSManagedObjectContext *moc = APPDELEGATE.managedObjectContext;
NSFetchRequest *request = [NSFetchRequest new];
[request setEntity:[NSEntityDescription entityForName:@"EntityC" inManagedObjectContext:moc]];
[request setPredicate:[NSPredicate predicateWithFormat:@"tag = YES"]];
NSError *fetchError = nil;
NSArray *children = [moc executeFetchRequest:request error:&fetchError];

childrenEntityC是与谓词匹配的对象数组。下一步是获取一组独特的EntityA对象,它们是这些对象的“祖父母”。我们可以在这里利用键值编码:

NSArray *grandParents = [children valueForKeyPath:@"parent.@distinctUnionOfObjects.parent"];

在这种情况下,为了提高效率,我们可能希望parent.parent在初始获取请求期间预取密钥路径:

[request setRelationshipKeyPathsForPrefetching:@[@"parent.parent"]];

希望这可以帮助!

于 2012-10-06T03:47:59.520 回答