Search code examples
iphoneioscore-data

Keypath error with Core Data SUBQUERY and NSFetchedResultsController


Apologies if this is a duplicate, 20 minutes of searching didn't yield this exact situation or a solution.

I have a Core Data stack with three classes XClass, YClass, and ZClass. XClass has a one-to-many relationship with YClass. YClass has a one-to-many relationship with ZClass.

Using an instance of NSFetchedResultsController, I'm trying to fetch all instances of XClass for which at least 1 YClass has at least 1 ZClass.

My predicate is defined as follows:

// ...stuff
NSFetchRequest * fetchRequest = [NSFetchRequest new];

NSEntityDescription * entity = [NSEntityDescription entityForName:NSStringFromClass([XClass class])
                                           inManagedObjectContext:managedObjectContext];
fetchRequest.entity = entity;

fetchRequest.predicate = 
[NSPredicate predicateWithFormat:@"0 < SUBQUERY(yObjects, $y, $y.zObjects.@count > 0).@count"];

// ..instantiate NSFetchedResultsController and perform fetch

This causes a fatal exception with the message: Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Keypath containing KVC aggregate where there shouldn't be one; failed to handle $y.zObjects.@count'

Elsewhere, I've successfully fetched YObject instances with the predicate [NSPredicate predicateWithFormat:@"zObjects.@count > 0"];

Can someone point me to what I'm doing wrong? Thank you much.


Solution

  • It seems that NSPredicate objects violently when you use collection operators in the predicate string for the SUBQUERY. It also appears that you cannot operate on a collection in the subquery predicate. That is unless the variable represents a collection in the predicate.

    BAD: SUBQUERY(yObjects, $y, $y.zObjects == NIL) > 0

    OK: SUBQUERY(yObjects, $y, SUBQUERY($y.zObjects, $z, $z == NIL) > 0) > 0

    The following expression will add all non-nil objects to the filtered collection returned by the SUBQUERY. In other words, the returned collection will contain all instances of XClass with instantiations of ZClass.

    [NSPredicate predicateWithFormat:@"yObjects.@count > 0 AND (SUBQUERY(yObjects, $y, (SUBQUERY($y.zObjects, $z, $z != NIL).@count > 0)).count > 0)"];