Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Core Data, try to use NSPredicate to filter a toMany relationship set but get the "to-many key not allowed here" error

Here is the model I have: http://www.girardet.ch/model.png

My goal is to retrieve all the Quotes with these criterias:

  • belong to a specific theme : the name_en attribute of Themes
  • order by relevancy
  • filtered by Authors (with the alias attribute of Authors)

Here is my code:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"ThemeEntries" inManagedObjectContext:_context];
[fetchRequest setEntity:entity];

NSSortDescriptor *sortDescriptor1 = [[NSSortDescriptor alloc] initWithKey:@"relevancy" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor1, nil];
[fetchRequest setSortDescriptors:sortDescriptors];

// predictate - filter
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"theme.name_en=%@ AND quotes.author.alias=%@",@"mytheme", @"myauthor"];

[fetchRequest setPredicate:predicate];

I get the "to-many key not allowed here" error.

If I instead use this predicate

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"theme.name_en=%@, @"mytheme"];

it works well and I can loop over the ThemeEntries that I get and get all my quotes... But it's not filtered by authors.

What can I do to filter by Authors?

like image 747
Ben Avatar asked Sep 05 '10 03:09

Ben


1 Answers

Your problem is that the relationship of one of you keypath is a to-many, to-many and the predicate does not know which particular object goes with which.

You have ThemeEntities<<-->>Quotes which is produces a set at each end. The quotes.author.alias keypath says "a set of quotes instances, each linked to author instances which in turn has an alias attribute." The predicate cannot process the set.

You need to use a subquery to jump a to-many keypath. The subquery is essentially a nested predicate which searches a set and returns another set of objects matching the nested predicate. Subqueries are poorly documented but they have the form:

SUBQUERY(collectionName,$collectionElementVariable,expression-with-$collectionElementVariable)

In this case, you are looking for any quote instances that has a author relationship with an alias matching the supplied string. Your predicate would need to look like:

@"theme.name_en=%@ AND (0!=SUBQUERY(quotes,$eachQuote,$eachQuote.author.alias=%@).@count)",@"mytheme", @"myauthor"

The subquery says, "Of the set of quotes, take each quote object and test if its author relationship object has an alias attribute matching 'myauthor'. Count the number of quote objects with that match. If the number is non-zero, return TRUE."

You need to use subqueries whenever you walk a keypath across a to-many relationship.

like image 80
TechZen Avatar answered Oct 05 '22 17:10

TechZen