Re: Core Data NSPredicate
Re: Core Data NSPredicate
- Subject: Re: Core Data NSPredicate
- From: Andreas Grosam <email@hidden>
- Date: Mon, 14 Mar 2011 10:45:12 +0100
On Mar 13, 2011, at 1:51 AM, Indragie Karunaratne wrote:
> Andreas,
>
> That predicate syntax (and block predicates) won't work in my case because I'm using them in a Core Data NSFetchRequest.
This is true only if you use a sqlite store - but this is also most likely ;)
If you were not using SQLite, this simple predicate should have worked with a fetch request:
NSPredicate* pred = [NSPredicate predicateWithFormat:@"ALL %@ IN {attr0, attr1}", terms];
where terms is an array (or better a set) of strings, and attr0 and attr1 are key paths for attributes of the managed object. Here, the values for the attributes for each candidate of the managed objects are used in the predicate.
The predicate becomes true only if all search terms are found in any of the values of the attributes.
You may have meant it the other way around, then the predicate would become:
NSPredicate* pred = [NSPredicate predicateWithFormat:@"ALL {attr0, attr1} IN %@", terms];
Anyway, as you already found out, this predicate would not work with a sqlite store type. The reason is, that a *fetch* predicate must be mapped to an equivalent sqlite query - which is not always possible.
The error isn't a parser error, though. It is actually an Invalid Argument Exception whose reason is "unsupported predicate" which is thrown when you try to *execute the fetch*. So, the task is to find another form of the predicate which will work with the sqlite store.
> I did, however, manage to solve this issue by using subpredicates:
This is fine, however I'm not completely confident that your compound predicate (below) actually expresses your original intent.
Consider, the prediacte
All tems IN attributes
is equivalent to
(term_0 IN attributes) AND (term_1 IN attributes) ... AND (term_n IN attributes)
So the code for this would look like this:
NSMutableArray* subPredicates = [[NSMutableArray alloc] initWithCapacity:[terms count]];
for (NSString* term in terms) {
NSPredicate* p = [NSPredicate predicateWithFormat:@"%@ IN {attr0, attr1}", term];
[subPredicates addObject:p];
}
NSPredicate* pred = [NSCompoundPredicate andPredicateWithSubpredicates:subPredicates];
[subPredicates release], subPredicates = nil;
[fetchRequest setPredicate:pred];
Regards
Andreas
>
> NSPredicate *basePredicate = [NSPredicate predicateWithFormat:@"(name CONTAINS[cd] $QUERY) OR (artist.name CONTAINS[cd] $QUERY)"];
> NSMutableArray *andPredicates = [NSMutableArray array];
> for (NSString *term in terms) {
> NSDictionary *substitution = [NSDictionary dictionaryWithObjectsAndKeys:term, @"QUERY", nil];
> NSPredicate *andPredicate = [basePredicate predicateWithSubstitutionVariables:substitution];
> [andPredicates addObject:andPredicate];
> }
> NSPredicate *finalPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:andPredicates];
>
> On 2011-03-12, at 6:17 AM, Andreas Grosam wrote:
>
>>
>> On Mar 12, 2011, at 3:36 AM, Indragie Karunaratne wrote:
>>
>>> I have an NSManagedObject that has the following string attributes:
>>>
>>> artist, albumArtist, composer, comments, and lyrics
>>>
>>> I need to write an NSPredicate that will take an array of search terms, and check if all of the above string attributes COMBINED contains every term in the search term array. I tried the following predicate format:
>>>
>>> NSArray *searchTerms = [NSArray arrayWithObjects:@"testing", @"search", nil];
>>> NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ALL %@ IN { artist, albumArtist, composer, comments, lyrics }", searchTerms];
>>>
>>> This triggered a parsing error and would not run. Is there any way I can do this in an NSPredicate, aside from creating a "search string" attribute in my data model containing a concatenated string of the above attributes?
>>
>>
>> You should not include the object where the predicate is run against into the parameters of the format string. Otherwise, you would get a constant expression, rather a predicate.
>>
>> Furthermore, when specifying an embedded string-list you need to quote the string elements.
>>
>> This should work then:
>>
>> NSArray* terms = ...
>> NSPredicate* pred = [NSPredicate predicateWithFormat:@"ALL self IN {'artist', 'albumArtist', 'composer', 'comments'}"];
>>
>> BOOL test = [pred evaluateWithObject:terms];
>>
>>
>> Note: you can use a ^block for the predicate as well.
>>
>>
>> Regards
>> Andreas_______________________________________________
>>
>> Cocoa-dev mailing list (email@hidden)
>>
>> Please do not post admin requests or moderator comments to the list.
>> Contact the moderators at cocoa-dev-admins(at)lists.apple.com
>>
>> Help/Unsubscribe/Update your Subscription:
>>
>> This email sent to email@hidden
>
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden