Realm: no se puede crear un object con el valor de key principal existente

Tengo una persona object con muchos perros. La aplicación tiene una página separada en la que muestra solo perros y otra página donde muestra los perros de la persona

Mi model es el siguiente

class Person: Object { dynamic var id = 0 let dogs= List<Dog>() override static func primaryKey() -> String? { return "id" } } class Dog: Object { dynamic var id = 0 dynamic var name = "" override static func primaryKey() -> String? { return "id" } } 

Tengo personas almacenadas en el Reino. La persona tiene una página de detalles donde buscamos y mostramos a sus perros. Si el perro ya existe, actualizo la última información para ese perro y añádalo a la list de perros de la persona. De lo contrario, cree un perro nuevo, guárdelo y añádalo a la list de personas. Esto funciona en conetworkingata.

 // Fetch and parse dogs if let person = realm.objects(Person.self).filter("id =\(personID)").first { for (_, dict): (String, JSON) in response { // Create dog using the dict info,my custom init method if let dog = Dog(dict: dict) { try! realm.write { // save it to realm realm.create(Dog, value:dog, update: true) // append dog to person person.dogs.append(dog) } } } try! realm.write { // save person realm.create(Person.self, value: person, update: true) } } 

Al intentar actualizar una persona con sus perros, el reino lanza una exception. No se puede crear un object con el valor de key primaria existente.

El problema aquí es que a pesar de que está creando un object Realm Dog completamente nuevo, en realidad no lo está persistiendo en la database, por lo que cuando llama a append , está intentando agregar una segunda copy.

Cuando llama a realm.create(Dog, value:dog, update: true) , si ya existe un object con esa ID en la database, simplemente está actualizando ese object existente con los valores en la instancia de dog que creó, pero esa instancia de dog sigue siendo una copy independiente; no es el object Dog en la database. Puede confirmar esto comprobando si dog.realm es igual a nil o no.

Entonces, cuando llama a person.dogs.append(dog) , porque el dog no está en la database, Realm intenta crear una input de database completamente nueva, pero falla porque ya hay un perro con esa ID.

Si desea anexar ese object de dog a una person , será necesario consultar a Realm para que recupere un object de dog apropiado que haga reference a la input en la database. Afortunadamente, esto es realmente fácil con objects de Realm respaldados por keys primarias, ya que puede usar el Realm.object(ofType:forPrimaryKey:) :

 if let person = realm.object(ofType: Person.self, forPrimaryKey: "id") { for (_, dict): (String, JSON) in response { //Create dog using the dict info,my custom init method if let dog = Dog(dict: dict) { try! realm.write { //save it to realm realm.create(Dog, value: dog, update: true) //get the dog reference from the database let realmDog = realm.object(ofType: Dog.self, forPrimaryKey: "id") //append dog to person person.dogs.append(realmDog) } } } try! realm.write { //save person realm.create(person .self, value: collection, update: true) } }