Question

I have a situation where I want to fetch objects from my core data store by the username key, but I want the comparison to be case-insensitive. The predicate I have is this:

username IN $usernames

I then do a variable substitution with an array of strings that are the usernames I want to find. It works but is case-sensitive. I'd like to do something like this, I think:

username IN[c] $usernames

Unfortunately that doesn't appear to work. The string comparison must still be happening in a case-sensitive way. (I don't get an error about it being an unsupported query.)

Is there a different way to write this predicate so it works the way I need or am I just missing something obvious here?

Was it helpful?

Solution

The case modifier on the IN operator is apparently ignored when executing a fetch against the SQLite store. (You omitted the store type from your question.)

I'd recommend filing a bug against the documentation so that this limitation/behavior can be documented.

I'd also recommend filing a feature request in the bug reporter so that this can be considered for future support.

In the meantime, you'll have to pull your fetch request out of the data model and build it up programatically. You can build a compound predicate OR predicate that does a case insensitive equality match for each of your values (and test that it meets your performance needs.)

Note that if you are supporting OS targets prior to 10.6 the case modifier on == is not supported, in which case yet another alternate solution will be required.

OTHER TIPS

You might try something like ANY $usernames LIKE[c] username. I've done something similar, where instead of the variable substution, I just have a key path like "persons.name", and that predicate works for me. Not sure if it works any differently with a variable there instead of a key path, but it's worth a shot.

Here is another workaround, but requires you to change the MOM.

Make username a full blown entity. Create the inverse relationship between username and whatever your other entity is.

Now for the fetch request, set the entity as "Username" then run this predicate (assuming a "name" property and "parent" property):

   [NSPredicate predicateWithFormat:"(name like[c] %@) && (parent == %@)", theUserName, theParentObject]

This may be overkill, but will allow you to run your search as desired.

Although this question is several years old I just stumbled upon the same problem and solved it like this:

NSArray  *values = @[@"FOO", @"bar" ,@"lorem"];
NSString *predicate;

predicate = @"value LIKE[cd] '";
predicate = [predicate stringByAppendingString:
             [values componentsJoinedByString:
              @"' OR  value LIKE[cd] '"]];
predicate = [predicate stringByAppendingString:@"'"];

NSLog(@"%@",  predicate);
// Output:
// value LIKE[cd] 'FOO' OR  value LIKE[cd] 'bar' OR  value LIKE[cd] 'lorem'

This creates a static predicate expression from the value list. Maybe it will be usefull to someone.

UPDATE 2:

Actually it seems like the updated solution below does not work with sqlite and produces an

'NSInvalidArgumentException',
reason: 'unimplemented SQL generation for predicate : ... (bad LHS)'

I think for array/dict/set comparisions and IN there are only keys allowed on the left side of the operator.

UPDATE:

After some research on expressions and predicates I found another aproach, that seems to work quite well:

NSPredicate *predicate =
   [NSPredicate predicateWithFormat:
     @"lowercase(value) IN %@", values];

This uses the function expression lowercase: to get the lowercase representation of the value. All that's left to do is to ensure that all entries of values are lowercase and you'll be able to use case insensitive IN expressions.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top