bmt22033
bmt22033

Reputation: 7240

Changing primary key property name on Realm Swift object model

I have a Realm (Swift) object that's existed in my app for about a year now. The model for this object looks like this:

class ChatMessage: Object {

    @objc dynamic var messageId: Int = generateId()
    // other properties omitted

    override static func primaryKey() -> String? {
        return "messageId"
    }
}

Now, I find myself needing to effectively rename the "messageId" property to "id" and make "id" the primary key. I need to do this because I need this object to conform to a particular protocol (from a framework that I don't control) and that protocol specifies that I need a "messageId" property of type String. Renaming seems to be the most straight forward explanation for what I'm trying to do but I realize that this might also be explained by saying that I want to:

  1. create a new "id" property (of type Int)
  2. copy the existing value of "messageId" to the "id" property (during migration)
  3. change the primary key to use "id" instead of "messageId"

In effect, what I want the object to look like after the change is:

class ChatMessage: Object {

    @objc dynamic var id: Int = generateId()
    // other properties omitted

    override static func primaryKey() -> String? {
        return "id"
    }
}

I have a migration block defined and I've tried a few different ways of accomplishing this but so far haven't had any luck. Without the migration block, I get the following in the Xcode debug console:

ERROR - Failed to open Realm! Error Domain=io.realm Code=10 "Migration is required due to the following errors:
- Property 'ChatMessage.messageId' has been removed.
- Property 'ChatMessage.id' has been added.
- Primary Key for class 'ChatMessage' has changed from 'messageId' to 'id'.

For what it's worth, I'm using Realm 5.50 and I've read through the docs at https://realm.io/docs/swift/latest/ and I see this statement:

Once an object with a primary key is added to a Realm, the primary key cannot be changed.

That makes it sound like this isn't possible to do with Realm anymore but I'm wondering if anyone can confirm that or if there is, in fact, a way to achieve this? Thanks!

Upvotes: 0

Views: 1640

Answers (2)

kamasuPaul
kamasuPaul

Reputation: 323

One day someone will come looking for this in flutter: The simple answer is to use the annotation @MapTo("_id")

class _Car {
  @PrimaryKey()
  @MapTo("_id")
  late ObjectId id;
  ...
}

Upvotes: 0

Jay
Jay

Reputation: 35648

You can actually change the primary key within a migration block. Suppose you have a object that looks like this, with 'localID' being the primary key

class TestClass: Object {
    @objc dynamic var localID = UUID().uuidString

    override static func primaryKey() -> String? {
        return "localID"
    }
}

and we want to change the primary key to _id. The migration block would look something like this

let vers = UInt64(3)
let config = Realm.Configuration( schemaVersion: vers, migrationBlock: { migration, oldSchemaVersion in
     print("oldSchemaVersion: \(oldSchemaVersion)")
     if (oldSchemaVersion < vers) {
        print("  performing migration")
        migration.enumerateObjects(ofType: TestClass.className()) { oldItem, newItem in
            let oldId = oldItem!["localID"]
            newItem!["_id"] = oldId

         }
     }
 })

I would suggest using _id instead of id so it will be compatible with MongoDB Realm in the future. See Define a Realm Schema

Upvotes: 2

Related Questions