I asked a question yesterday where I really should have started with a simpler example. Having distilled my question to the basics, I've managed to solve my problem using existing SO questions and answers.
I'm summarising my question here (and providing my own solution) because I don't think there are any posts that explain this clearly enough. Being new to Core Data and struggling to get away from SQL concepts, I'd welcome feedback on how appropriate my solution is, and if there are better ways of modelling the problem.
Question
Given the following object model, that has three entities A, B and C, each linked by to-many relationships:
How is it possible to identify the parent A entities, that have grandchildren C entities with a particular attribute? By example, using these sample entities and their relationships:
How can I find our which entity A s have child entity C s with the Tag:Yes?
Solution
I've been able to achieve this is using the SUBQUERY
keyword of NSPredicate
. Here is the code snippet that worked for me (assuming you've set up your managed object context etc):
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];
Breaking the all important NSPredicate string onto several lines:
(0 != SUBQUERY(child,
$a,
(0 != SUBQUERY($a.child,
$child,
$child.tag == %@).@count)
).@count
)
The important part is we are selecting the EntityA
to work from and then in the nested subquery working through the child
relationships of the entities. I expect this can be repeated for several depths. Not the most intuitive thing to put together... but it works. Comments welcome.