Ben Pious
Ben Pious

Reputation: 4805

Predicate Only Returns One Object

I am using Core Data for a strategy game. A player of this game has several Characters, which can be assigned to Armies. A Character has a many to many relationship with the armies to which it belongs, the inverse of which is the Characters many to many relationship of Army.

I would like to prevent the player from assigning a character to the same army repeatedly. To that end, when formulating a fetch request in a view controller to allow the player to select Characters to assign to the current Army, I would like to filter out all the Characters who are already in the army. What I have now is below.

    NSFetchRequest* allCharacters = [[[NSFetchRequest alloc] init] autorelease];
    [allCharacters setEntity: [NSEntityDescription entityForName: @"Character" inManagedObjectContext: _managedObjectContext]];
    allCharacters.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey: @"name" ascending: YES]];
    [allCharacters setPredicate: [NSPredicate predicateWithFormat: @"0 != SUBQUERY(armies, $element, $element.name like %@)", currArmy.name]];
    _fetchedObjectController = [[NSFetchedResultsController alloc] initWithFetchRequest: allCharacters managedObjectContext: _managedObjectContext sectionNameKeyPath: nil cacheName: @"Armies"];
    NSError* error;
    [_fetchedObjectController performFetch: &error];

This code, however, only returns one Character who meets the criteria. My attempts to google the problem, or even to find some authoritative documentation about this command that might be helpful have failed. What am I doing wrong -- or is there a better way altogether to do what I want?

Upvotes: 0

Views: 87

Answers (1)

Martin R
Martin R

Reputation: 539685

  • LIKE in a predicate does a simple wildcard matching (with ? and * as wildcard characters). You probably want to compare with a simple ==.

  • SUBQUERY() returns a collection of objects and is usually used together with @count in a predicate.

  • Instead of comparing $element.name with currArmy.name, you can compare $element with currArmy directly.

The following predicate should work to find all objects that are not related to the current army:

[NSPredicate predicateWithFormat: @"SUBQUERY(armies, $element, $element == %@).@count == 0", currArmy]

(The SUBQUERY is only needed because NOT ANY does not work correctly in a Core Data predicate, compare Core Data NSPredicate with to-Many Relationship.)

Upvotes: 1

Related Questions