Enhancement to NSFetchRequest/NSPredicate/NSFetchedResultsController to better support many-to-many

Originator:amorya
Number:rdar://17063629 Date Originated:Thu 29 May 2014
Status:Open Resolved:
Product:iOS SDK Product Version:7.1
Classification:Enhancement Reproducible:Always
 
Consider the following data model:

Author ≪--≫ Article

In my iOS app, I am trying to display a table view with one section per author, the contents of each section showing the articles that author has written. Yes, this means that any article with multiple authors will be shown more than once in the table view. This is a reasonably common use case (I have encountered it in multiple apps).

In SQL, I would do this:

SELECT author.name AS selectedAuthorName, authorID AS selectedAuthorID, article.* 
FROM authorArticleLinks 
LEFT JOIN author ON authorID = author.id 
LEFT JOIN article ON articleID = article.id
WHERE author.isBestselling = TRUE
ORDER BY author.name, article.date

That is to say, I'm querying on the author-article linking table, asking for every field from article, plus the ID and name of the author through which we came to fetch each result. I've put the WHERE clause in as an example of something I might want to filter on.

I'd like a way to do this in a single query through Core Data. Here's a suggestion for how it could be done.

NSFetchRequest *req = [NSFetchRequest fetchRequestWithEntityName:@"Article"];
req.categorizationRelationshipName = @"authors"; // the key on Article that represents the relationship
req.categorizationSortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"name"]];
req.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"date"]];
req.categorizationSubstitutionVariable = @"a"; // for use in the predicate
req.predicate = [NSPredicate predicateWithFormat:@"$a.isBestselling = YES"];
req.fetchWithCategorizationObjects = NO.

Run this (with executeFetchRequest), and you  get an NSArray of Article objects. Some articles may be in there more than once, as mentioned.

The real power comes when we do req.fetchWithCategorizationObjects = YES. In that circumstances, the user gets back an array of NSCategorizationResult objects.

An NSCategorizationResult has two read-only properties:

NSManagedObject *categorizationObject;
NSManagedObject *returnedObject;

So in this case, for each categorizationResult in our NSArray, we'd be able to get the categorizationObject (the author through which we got this result) and also the returnedObject (the article in question).

The best thing is, this would all work with NSFetchedResultsController. You'd be able to turn on fetchWithCategorizationObjects on its fetch request, then you could use a sectionNameKeyPath such as @"categorizationObject.name".

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!