Realm-cocoa: Realm.io Primary key property has duplicate values after migration

Created on 21 Nov 2016  路  4Comments  路  Source: realm/realm-cocoa

Same issue with this

Code Sample

@interface RLMProfile: RLMObject
@property NSString *objectID;
@property NSString *name;
...
@end

@implementation RLMProfile

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

This is first version of my model, there are 8 entities in realm.

Then I set objectID to required:

@implementation RLMProfile
+ (NSString *)primaryKey {
  return @"objectID";
}
+  (NSArray<NSString *> *)requiredProperties{
  return @[@"objectID", @"name"];
}
@end

And add an empty migration block:

  RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
  config.schemaVersion = 1;
  config.migrationBlock = ^(RLMMigration *migration, uint64_t oldSchemaVersion) {
    // We haven鈥檛 migrated anything yet, so oldSchemaVersion == 0
    if (oldSchemaVersion < 1) {
      // Realm will automatically detect new properties and removed properties
      // And will update the schema on disk automatically
    }
  };

  [RLMRealmConfiguration setDefaultConfiguration:config];
  [RLMRealm defaultRealm];

I believe this should work, but when I rebuild and run my app again, realm throws this error and stopped:
Realm.io Primary key 'objectID' property has duplicate values after migration.

But in fact there is no duplicate values for objectID, this is all my models from realm browser:
_How do I insert image here???_

Version of Realm and Tooling

ProductName: Mac OS X
ProductVersion: 10.11.6
BuildVersion: 15G31

/Applications/Xcode.app/Contents/Developer
Xcode Version 8.1 beta (8T47)

/usr/local/bin/pod
1.0.1

/bin/bash
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin15)

(not in use here)

/usr/bin/git
git version 2.7.4 (Apple Git-66)
```

T-Help

Most helpful comment

@TaoistKing This is intended behavior. If the property is changed from nullable to required, auto-migration automatically sets a fixed value (For String property, an empty string was set). Therefore, all objectID properties will be empty. That is why the primary key is duplicated.

To avoid this, you should write migration block to copy the value from the old object to the new object.

RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
config.schemaVersion = 1;
config.migrationBlock = ^(RLMMigration *migration, uint64_t oldSchemaVersion) {
    // We haven鈥檛 migrated anything yet, so oldSchemaVersion == 0
    if (oldSchemaVersion < 1) {
        [migration enumerateObjects:[RLMProfile className] block:^(RLMObject * _Nullable oldObject, RLMObject * _Nullable newObject) {
            newObject[@"objectID"] = oldObject[@"objectID"];
            newObject[@"name"] = oldObject[@"name"];
        }];
    }
};
[RLMRealmConfiguration setDefaultConfiguration:config];

All 4 comments

Besides I'm Not using pod for realm, I just downloaded the framework from https://realm.io/docs/objc/latest/#installation

@TaoistKing This is intended behavior. If the property is changed from nullable to required, auto-migration automatically sets a fixed value (For String property, an empty string was set). Therefore, all objectID properties will be empty. That is why the primary key is duplicated.

To avoid this, you should write migration block to copy the value from the old object to the new object.

RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
config.schemaVersion = 1;
config.migrationBlock = ^(RLMMigration *migration, uint64_t oldSchemaVersion) {
    // We haven鈥檛 migrated anything yet, so oldSchemaVersion == 0
    if (oldSchemaVersion < 1) {
        [migration enumerateObjects:[RLMProfile className] block:^(RLMObject * _Nullable oldObject, RLMObject * _Nullable newObject) {
            newObject[@"objectID"] = oldObject[@"objectID"];
            newObject[@"name"] = oldObject[@"name"];
        }];
    }
};
[RLMRealmConfiguration setDefaultConfiguration:config];

Thanks.
Isn't it better to copy from old value than set an empty string? When old value is nil then an empty string would be set.

This is a really interesting case and the current behavior might be not completely correct. I've create another issue to track it: https://github.com/realm/realm-cocoa/issues/4370.

Thanks for reporting this issue, @TaoistKing!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ciminuv picture ciminuv  路  3Comments

jpsim picture jpsim  路  3Comments

carvalho-oak picture carvalho-oak  路  3Comments

i-schuetz picture i-schuetz  路  3Comments

javierjulio picture javierjulio  路  3Comments