Luka Vujnovac
Luka Vujnovac

Reputation: 22

how to add primary key to realm objects

I am trying to make my realm objects able to edit from the app. This is my class:

import Foundation
import RealmSwift

class Category: Object {
    @objc dynamic var name: String = ""
    let items = List<Item>()
}

 

this is how I make instances of that class:

        let action = UIAlertAction(title: "Add", style: .default) { action in
            
            let newCategory = Category()
            newCategory.name = textField.text!
            
            self.save(category: newCategory)
        }
    
       

this is my edit method:


func edit(category: Category) {
        do {
            try realm.write {
                realm.add(category, update: .all)
            }
        }catch {
            print("error editing category \(error)")
        }
    }

and this is how I call my edit method inside IBAction for when edit button pressed

let saveAction = UIAlertAction(title: "Save Changes", style: .default) { action in
            
            let editedCategory = Category()
            editedCategory.name = textField.text!
            
            self.edit(category: editedCategory)

        }

the error I am getting is: "Terminating app due to uncaught exception 'RLMException', reason: ''Category' does not have a primary key and can not be updated'"

I have tried adding the primary key in my category class, but is still did not work. Any help?

Upvotes: 0

Views: 1733

Answers (1)

Jay
Jay

Reputation: 35648

A lot of this is covered in the Realm guide Read and Write Data but let me also provide some details. Note, this answer reflects Swift pre-10.10.0 and some things have changed in later versions.

The method you're trying to use

realm.add(category, update: .all)

is called an 'upsert' and requires a primary key in the object.

An upsert either inserts or updates an object depending on whether the object already exists. Upserts require the data model to have a primary key.

So let's re-tool the Category object to include a primary key _id

class Category: Object {
    @objc dynamic var _id: ObjectId = ObjectId.generate()
    @objc dynamic var name: String = ""
    let items = List<Item>()

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

Then, when an object is created

let newCategory = Category()
newCategory.name = textField.text!
let realm = try! Realm()
try! realm.write {
   realm.add(newCategory)
}

it will have a primary key

From then forward you can either modify the object within a write or upsert it via it's primary key.

let someId = //the id of the newCategory created above
try! realm.write {
   let anotherCat = Category(value: ["_id": someId, "name": "Frank"])
   realm.add(anotherCat, update: .modified)
}

The above code will update the original newCategory object with a new name because the _id is the same

Upvotes: 1

Related Questions