views:

547

answers:

3

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?

+3  A: 

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.

Jim Correia
For your last point, do you mean == when used as a predicate string? Does it still work when building the predicate programmatically? I'm targeting 10.5.
Sean
After testing on 10.5, it looks like it will not work. Dammit! It seems my only option then is to build an expression that is like: "username CONTAINS[cd] $u AND $u CONTAINS[cd] username". Sigh.
Sean
And no. Even using two CONTAINS won't work because my overall expression is an OR of a bunch of other predicates and it seems I cannot have an OR set that contains AND predicates. Blah. After going about this all wrong, I switched to using LIKE[cd] and escaping the * and ? characters from my input string. Works like a charm. There seem to be a rather distressing number of limitations in predicate handling...
Sean
LIKE[c] and escaping * and ? is the typical solution when you must deploy on 10.5.
Jim Correia
A: 

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.

Brian Webster
Unfortunately, that predicate will not work with an SQLite store. (Unimplemented SQL generation.) In situations where it does work, take care to make sure the string sin $usernames have literal LIKE wildcard characters escaped.
Jim Correia
A: 

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.

Corey Floyd