Search code examples
core-datanspredicateone-to-manyrelationshipnsfetchrequest

Filtering with NSPredicate in one-to-many relationships


I tried a lot of the solutions in stackoverflow but I'm not able to find a valid one. I have a core data model with two entities: Client and Destination. Both are wrapped by NSManagedObjectsubclasses.

Client has some properties and a one-to-many relationship called destinations. Destination has a property called default_dest that is wrapped by a NSNumber and an inverse relationship called client.

I have a UITableViewController where I'm using the following fetchedController property. The request works well. I'm able to retrieve clients stored in SQLite.

if (fetchedResultsController) 
    return fetchedResultsController;

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Client" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];

[fetchRequest setFetchBatchSize:20];

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"code" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];

[fetchRequest setSortDescriptors:sortDescriptors];

fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];

fetchedResultsController.delegate = self;

[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];

return fetchedResultsController;

I would make another step. I would now filter the destinations retrieved from the previous request (that are contained in destinations NSSet) for each client. In particular, the destination can be added only if its default_dest value is 1.

To fix this specification I tried to add an NSPredicate like the following:

NSPredicate* predicate = [NSpredicate predicateWithFormat:@"ANY destinations.default_dest == %@", [NSNumber numberWithInt:1]];

Then I set it in fetchRequest as:

[fetchRequest setPredicate:predicate];

Each time I run the request, it returns a "to-many-relationship fault destinations...". What does it mean?

I've read iphone-core-data-relationship-fault but I don't understand what does it mean.

So, my questions are: Is it possible to reach a similar goal? If yes, do you have any suggestions?

Notes

Obviously I could iterate over destinations set but I don't know if could be an expensive iteration and how many records there are.


Solution

  • For those interested in.

    You need to say to your fetch request to prefetch relationships using

    - (void)setRelationshipKeyPathsForPrefetching:(NSArray *)keys
    

    For example:

    [fetchRequest setRelationshipKeyPathsForPrefetching:[NSArray arrayWithObjects: @"destinations", nil]];
    

    In this manner Core Data prefetch the relationships you have specified and doesn't fire fault.

    In addition you can limit the number of results for your fetch request by limiting it using:

    - (void)setFetchLimit:(NSUInteger)limit
    

    Hope it helps.