21

I have noticed that setting PK is not obligatory in Realm and simply can be omitted. But in documentation is stated that:

Indexes are created automatically for primary key properties.

And I'd like to clear up some questions:

1) What is the default value for PK is defined by Realm, if I don't assign it by myself. Is it hash or whatever ? (If I don't set PK and call [MyRealmObject primaryKey] it returns nil)

2) If this implicit PK is indexed by default ? Should I worry about it, because if it is not indexed, does it mean that it affects the general performance of this Entity (for example,fetching objects) ?

3) Is it a good practice to define PK every time for each RLMObject subclass or it isn't necessary for Realm and simply may rely on it's internal realization defined by Realm itself?

David
  • 1,061
  • 11
  • 18

2 Answers2

19

(Disclaimer: I work for Realm.)

Yep! Setting a primary key in Realm isn't obligatory, nor necessary, which is why it's completely up to the developer and the requirements of the app to determine whether it's necessary or not in their implementation.

In response to your questions:

1) There are no default values; you specify one of your own properties as a primary key. primaryKey returns nil by default since you need to override that yourself in order to indicate to Realm which property you want to act as a primary key. Some users have set integers as primary keys, but more often than not, using a UUID string is the most common.

2) There's no implicit primary key. You must use the [RLMObject primaryKey] method to explicitly state which property is the primary key, and THEN it will be indexed. :)

3) In my own (spare-time) development experience, I usually find having a primary key makes it a lot easier to identify and handle specific objects. For example, if you're passing an object across threads, you can simply pass the primary key value and use [RLMObject objectForPrimaryKey:] to refetch the object. Obviously this depends on your own implementation requirements. You probably shouldn't add a primary key unless you find out you really need one.

As an example, here's what you would add to your RLMObject subclass if you wanted to set a UUID string as a primary key:

@interface MyObject : RLMObject

@property NSString *uuid;

@end

@implementation MyObject

+ (NSString *)primaryKey
{
   return @"uuid";
}

+ (NSDictionary *)defaultPropertyValues
{
   @{@"uuid": [[NSUUID UUID] UUIDString]};
}

@end

I hope that helped!

Addendum: To elaborate upon some of the comments made below, primary keys are explicitly necessary for any Realm APIs that change their functionality depending on if an object with the same key already exists in the database. For example +[RLMObject createOrUpdateInRealm:] will add a new Realm object to the database if an object with that primary key doesn't already exist, and will simply update the existing object otherwise.

As such, in these instances where a primary key is a critical component of the subsequent logic, they are required. However, since these APIs are a subset of the different ways in which it is possible to add/update data in Realm, if you choose to not use them, you still not required to have a primary key.

TiM
  • 15,812
  • 4
  • 51
  • 79
  • 5
    Thanks Tim. Also have found that object without PK cannot be updated if try to perform `addOrUpdateObject:` method, Realm rises `'RLMException', reason: 'YourClass' does not have a primary key and can not be updated'` – David Sep 07 '15 at 13:57
  • No worries! Oh! I didn't actually know that. I assumed it just defaulted to adding objects each time if you didn't define a primary key. Thanks for that! – TiM Sep 07 '15 at 13:59
  • 1
    Encountered the comment that @David post, and still agree, I get the same error. Therefore, you **must** set primary key in case you need to update the object. Should your answer by revised? – Idan Jul 03 '16 at 18:49
2

The horse has been beaten to death already, but I couldn't help but reference the Realm code which throws an exception if a Realm Object is created or updated without having a primary key.

+ (instancetype)createOrUpdateInRealm:(RLMRealm *)realm withValue:(id)value {
    // verify primary key
    RLMObjectSchema *schema = [self sharedSchema];
    if (!schema.primaryKeyProperty) {
        NSString *reason = [NSString stringWithFormat:@"'%@' does not have a primary key and can not be updated", schema.className];
        @throw [NSException exceptionWithName:@"RLMExecption" reason:reason userInfo:nil];
    }
    return (RLMObject *)RLMCreateObjectInRealmWithValue(realm, [self className], value, true);
}
Nicola Giancecchi
  • 3,045
  • 2
  • 25
  • 41
Stephen Paul
  • 2,762
  • 2
  • 21
  • 25
  • For this particular API call, yes a primary key property is required. This is because in order to handle the 'create vs update' behavior, it's necessary to have a mechanism to tell if this object already exists in Realm or not (Otherwise a new object will simply be added every single time it's called). But this API isn't the only way to add/change data in Realm, and if you don't use it, you still don't need to add a primary key to your object model. :) – TiM Dec 13 '16 at 18:06
  • Yeah, that makes a ton of sense. Thanks @TiM. – Stephen Paul Dec 14 '16 at 16:37