marco.marinangeli
marco.marinangeli

Reputation: 901

NSPredicate with AND in one-to-many relationships

I'm new to NSPredicate so i would appreciate if someone would tell me if i'm on the right way..
The problem: (the classes are sublclasses of NSManagedObject)
I've got a Player Class with this field:

@property (nonatomic, retain) NSSet *hisNumbers; //it's a set of Numbers

The Numbers Class is like this:

@property (nonatomic, retain) NSNumber * first;
@property (nonatomic, retain) NSNumber * second;
@property (nonatomic, retain) Season *forSeason; //it's one-to-one relationship with a Season Object
@property (nonatomic, retain) Player *owner; //one-to-one with Player
@property (nonatomic, retain) NSNumber * isPresent;

The Season Class has got these parameters:

@property (nonatomic, retain) NSSet *seasonGames; //set of Game
@property (nonatomic, retain) NSSet *numbers; //set of Numbers (inverse of forSeason)

What i'm trying to do is a method that takes a season object and gives me back all the players of that season...
this is my try:

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Player" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc]init];
[request setEntity:entity];

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

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(ANY SELF.hisNumbers.isPresent == %@) AND (ANY SELF.hisNumbers IN %@)",[NSNumber numberWithBool:YES],season.numbers];

but it doesn't work.. the two parts of the query seems to work separately, but maybe it's just a coincidence...

Now it returns every player which has a number with the flag 'isPresent == YES' and another number which is member of 'season.numbers'. What i need, instead, are the players which has got a single 'numbers' that matches both criteria at once...

If you need more details, let me know.. Thanks all

Upvotes: 2

Views: 597

Answers (1)

Martin R
Martin R

Reputation: 539685

Your predicate is true for a player which has a number with isPresent == YES and a possibly different number which is member of season.numbers.

To find players which have (at least one) number that matches both criteria, you probably have to use a SUBQUERY (at least I do not know a simpler solution).

Also you can simplify

"hisNumbers IN %@", season.numbers

to

"hisNumbers.forSeason == %@", season

This gives the following predicate, which hopefully works for you:

[NSPredicate predicateWithFormat:@"SUBQUERY(hisNumbers, $x, $x.isPresent == %@ AND $x.forSeason == %@).@count > 0",
     [NSNumber numberWithBool:YES], season]

(See expressionForSubquery:usingIteratorVariable:predicate: in the "NSExpression Class Reference", where a similar problem and the SUBQUERY solution is documented).

Upvotes: 6

Related Questions