Search code examples
ioscore-datauniquensmanagedobjectkey-value-observing

Core Data: best way of checking the uniqueness of an attribute


As far as I know, there is no way of setting an entity's attribute as unique through Core Data, neither programmatically nor in Xcode's editor... I need to make sure that certain managed objects can't be created if there are collisions with the values of the attributes I want to be unique, and I've been reading some posts dealing with that.

I've found a couple of approaches (e.g. Core Data unique attributes):

  1. To use -validateValue:forKey:error:
  2. To write some kind of custom method to check if the attribute's value already exists

What should the most recommendable option be?

Thanks


Solution

  • You're going to need some kind of custom code, whether you put it in validateValue:forKey:error: or in a custom method or somewhere else.

    Whether to use the built-in validation method is really a matter of how you prefer to organize your code. I'd prefer to do something like

    1. Check to see if the value is unique.
    2. If so, then insert a new instance.

    That's partly because I find the built-in validation scheme to be a pain, but mostly it's because that code will run every time you save changes to an object. If your check is in validateValue:forKey:error:, you'll run it repeatedly, even after you've verified that the value is unique. Then again maybe you need to do that, so the best answer in your case depends on a bigger picture of how your app needs to work.

    The simple way to approach validation is by doing a fetch with a predicate identifying the key and value that you need to check. The one change I'd make to the common fetching approach as described in the other answer is that I'd use countForFetchRequest:error: instead of executeFetchRequest:error:. It doesn't sound like you actually need to fetch existing objects during validation, you just need to know whether any exist, so just check that.

    Depending on the type of the unique attribute, you may be able to reduce the performance hit that you're going to take by doing this. For example, if it's a string. Checking all existing strings for a match is relatively expensive. On the other hand checking a bunch of existing integers is cheap. In that case you might find it worthwhile to add a numeric property to your entity type that stores a numeric hash of the unique string value. Use the hash only when checking uniqueness. It'll be a hell of a lot faster than looking for matching strings, and NSString even has a handy hash method to calculate the value for you.