CoreData :NSFetchedResultsController 一对多对多的关系

Posted

技术标签:

【中文标题】CoreData :NSFetchedResultsController 一对多对多的关系【英文标题】:CoreData :NSFetchedResultsController one to many to many to many relationship 【发布时间】:2015-06-02 00:01:04 【问题描述】:

我在开发应用程序时使用的是核心数据,核心数据对象如下所示:

给出剧院名称和流派名称我想显示演员名称。任何人都知道构建NSPredicate 的方法吗?

【问题讨论】:

模型似乎关闭了。电影有戏院,戏院有电影。应该是直接关系。电影有类型,但剧院没有类型。 (不是剧院是喜剧,而是电影。) @PetahChristian 影院,类型关系只是对每个影院的电影进行分类的方式 我了解,但与现实世界的关系不符。如果有人在寻找喜剧,他们会想看看什么电影是喜剧,而不是什么剧院是喜剧。 (剧院可能放映一部喜剧电影,但剧院本身不是喜剧。)人们想知道剧院正在播放什么电影,但没有直接关系。这就是我要说的。您正在使简单请求的谓词变得更复杂,就像这个 Actors 问题必须通过 Genres 一样,而该查询与 Genres 无关。 【参考方案1】:

您可以使用 SUBQUERY 构建深入“对多”关系的 NSPredicate:

    // Set predicate
NSPredicate *requestPredicate = [NSPredicate predicateWithFormat:@"SUBQUERY(genres, $g, ANY $g.movies.name == %@).@count != 0",  @"Batman vs Superman"];
[fetchRequest setPredicate:requestPredicate];

更新

根据您更新的示例,您需要这样的嵌套子查询:

 NSPredicate *requestPredicate = [NSPredicate predicateWithFormat:@"SUBQUERY(movies, $m, ANY $m.genres.name == %@).@count != 0 AND SUBQUERY(movies, $m, SUBQUERY($m.genres, $g, ANY $g.theaters.name == %@).@count != 0).@count != 0", @"Action", @"Harkins"];

这是一个示例 Cast 实体提取:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Cast" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:NO];
NSArray *sortDescriptors = @[sortDescriptor];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
// Set predicate
NSPredicate *requestPredicate = [NSPredicate predicateWithFormat:@"SUBQUERY(movies, $m, ANY $m.genres.name == %@).@count != 0 AND SUBQUERY(movies, $m, SUBQUERY($m.genres, $g, ANY $g.theaters.name == %@).@count != 0).@count != 0", @"Action", @"Harkins"];
[fetchRequest setPredicate:requestPredicate];
// Fetch
NSError *error = nil;
if (![aFetchedResultsController performFetch:&error]) 
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);

// Check fetched objects
NSArray *fetchedObjects = [aFetchedResultsController fetchedObjects];
for (Cast *eachCast in fetchedObjects) 
    NSLog(@"Each Cast name: %@", eachCast.name);

只需将@"Action" 替换为所需的流派名称,将@"Harkins" 替换为剧院名称。

以下是我设置核心数据模型的方法:

【讨论】:

感谢您的解决方案,但在您的解决方案中,您正在根据电影名称进行查询。例如,在我原来的问题中。我有电影院名称“西雅图”和流派名称“科幻”。我想列出所有在影院放映的电影的所有演员类型(西雅图/科幻)。 根据您的示例更新了我的答案。 @user2924482 你能用嵌套的子查询获得过滤的Actor吗?

以上是关于CoreData :NSFetchedResultsController 一对多对多的关系的主要内容,如果未能解决你的问题,请参考以下文章

CoreData(iOS):是不是需要创建数据库才能使用CoreData?coredata可以对简单的平面文件进行操作吗? [关闭]

CoreData 本地数据存储

CoreData与CloudKit同步时将图像保存到CoreData?

RestKit + CoreData:从CoreData缓存中排除某些对象

Coredata — 入门使用

认识CoreData—初识CoreData