1

I am trying to create a fetchRequest that shows me all values that are not already in another array. This code returns the array I expect:

NSArray *questionChoices = [self.currentQuestionChoiceGroup.questionChoices allObjects]; 
NSArray *filteredQuestionChoices  = [questionChoices filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"NONE %@ == code", myarr]];

myarr contains 1 item, and that 1 item is excluded from the filtered results, as expected. However, this code doesn't work:

NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:@"QuestionChoice" inManagedObjectContext:self.managedObjectContext];
request.predicate = [NSPredicate predicateWithFormat:@"NONE %@ == code AND questionChoiceGroup == %@", myarr, self.currentQuestionChoiceGroup];

When I execute this fetch request, I get all the questionChoices that belong to the current questionChoiceGroup, including the one that has a code that's in myarr. It seems to completely ignore the first part of the AND statement.

I can't see any difference between the two that should lead to different results. Can anyone help?

EDIT Simpler explanation:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"questionChoiceGroup == %@ AND NONE %@ == code", self.currentQuestionChoiceGroup, [NSArray arrayWithObject:@"A"]];

NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"displayOrder" ascending:YES]];
request.entity = [NSEntityDescription entityForName:@"QuestionChoice" inManagedObjectContext:self.managedObjectContext];

request.predicate = predicate;
NSArray *filteredQuestionChoices1 = [self.managedObjectContext executeFetchRequest:request error:nil];
NSLog(@"my filtered question choices 1: %@", [filteredQuestionChoices1 valueForKey:@"code"]);   

NSArray *filteredQuestionChoices2  = [filteredQuestionChoices1 filteredArrayUsingPredicate:predicate];
NSLog(@"my filtered question choices 2: %@", [filteredQuestionChoices2 valueForKey:@"code"]);

filteredQuestionChoices1 contains an item with a code of "A". filteredQuestionChoices2 does not have that item. How can the second predicate filter out anything that the first predicate didn't filter out? Both statements use the exact same predicate. Why am I getting objects back from the fetchedRequest if the exact same predicate will filter those objects out if I use the predicate on the array?

4

3 に答える 3

4

I'd try reworking your predicate a bit. Instead of:

[NSPredicate predicateWithFormat:@"NONE %@ == code", myarr]

Try:

[NSPredicate predicateWithFormat:@"NOT(code IN %@)", myarr]

I think the latter would probably be a bit easier for CoreData to translate into a corresponding SQL condition.

于 2011-03-04T19:10:12.430 に答える
1

Check out Fetch Predicates and Sort Descriptors in the Core Data Guide.

If you are using an SQL based data store (eg, SQLite) then the predicate is translated to SQL and invoked by the database, not by Cocoa. So you can get different behavior than you would see against a standard array and there are also constraints on what is supported. Specifically, there are limits on ALL, ANY, and IN operations (and your NONE operator is the equivalent of NOT( ANY ... )).

It looks you're trying to do your NONE operation against an array that you're supplying as an argument, rather than an array of data pulled from within the database. I'm willing to bet that's where the predicate to SQL translation is stumbling.

于 2011-03-05T05:34:33.320 に答える
0

When there are two parts to a statement using AND, wrap each part in parenthesis. Additionally when making comparisons to dynamic property names, %K is the appropriate format specifier.

request.predicate = [NSPredicate predicateWithFormat:@"(NONE %K == code) AND (questionChoiceGroup == %@"), myarr, self.currentQuestionChoiceGroup];

An example from Apple's Predicate Programming Guide:

Cocoa supports a wide range of types of predicate, including the following:

  • Simple comparisons, such as grade == 7 or firstName like 'Mark'

  • Case or diacritic insensitive lookups, such as name contains[cd] 'citroen'

  • Logical operations, such as (firstName beginswith 'M') AND (lastName like 'Adderley')

于 2011-03-01T22:16:12.173 に答える