1

I have this schema:

class A: Object {
    var idA = ""
    var b: B?
    override class func primaryKey() -> String {
        return "idA"
    }
}

class B: Object {
   var idB = ""
   var name = ""
   override class func primaryKey() -> String {
        return "idB"
    }
}

So if i want to save an A object:

func updateA(a: A, b: B) {
 do {
   try realm.write {
       a.b = b  //Here i get the excepcion
       realm.add(a, update: true)
   }
 } catch { error 
 } 
}

When i call update i can't assign b to a.b, i get: *** Terminating app due to uncaught exception 'RLMException', reason: 'Can't create object with existing primary key value "bKey".' If the b object already exists in the database with that primary key i get that, but if its a new object it works. Im pretty sure long time ago this worked as expected Notice i want to save A updating the B object if one of its properties has changed, like name. And i dont wanto to create another B object, just use the b object that already passed.

Godfather
  • 4,040
  • 6
  • 43
  • 70

2 Answers2

-1

It's as expected isnt it, you are adding the b that already created to create a similar one, that's not possible since you are already having that b with that primary key already

What you should do is just create a with another new b, not create b first then assign to a

Tj3n
  • 9,837
  • 2
  • 24
  • 35
  • i want to b be updated, not inserting another B. So thats why both B have the same primary key. – Godfather Nov 10 '16 at 11:33
  • Did you create a new B with similar primary key, or you fetched it? :/ And have you tried to change B property alone, not assign it with new B? like change b.name only – Tj3n Nov 10 '16 at 11:38
  • 1
    B whats created with another inserting of A. B is not actually fetched from realm, its another instance, let b = B(), b.id = "previousIdOfB", b.name= "updatedB". It comes from an API (both, a and b). – Godfather Nov 10 '16 at 11:41
  • That's the reason why you got crash i think, the Realm's `Object` is not only consist of your property that you declare, it included many things else (coz its subclassed), so you dont create new one even with similar prim key, you just fetched it and change it's property ;) – Tj3n Nov 10 '16 at 11:42
  • 1
    So i have to fetch OLD_B from realm, update the properties with NEW_B (from api), and then, add OLD_B to A? – Godfather Nov 10 '16 at 11:46
  • yep, thats how you do it – Tj3n Nov 11 '16 at 02:47
-1

If an Object doesn't already belong to a Realm, setting it as a child object will also try and add it to the Realm. In this case, since this appears to be a copy of b and not a direct reference to the record in the database, it's being treated as a new record with a conflicting primary key attempting to be added.

If you already have a copy of b in the database, you can grab an explicit reference to that one by using realm.object(ofType:forPrimaryKey:):

func updateA(a: A, b: B) {
    do {
        let bInDatabase = realm.object(ofType: B.self, forPrimaryKey: b.idB)
        try realm.write {
            a.b = bInDatabase
            realm.add(a, update: true)
        }
    } catch { error } 
}
TiM
  • 15,812
  • 4
  • 51
  • 79
  • so if i dont know if b already exists would be: let b = fetchBfromDataBase ?? b. ? – Godfather Nov 11 '16 at 06:15
  • isnt weird that if 'a' its also also fetched from API, and 'b' from api, i can add it to realm and both objects gets updated wihtout needing to fetch them both? – Godfather Nov 11 '16 at 06:16
  • Last comment update: a doesn't exist in realm but b yes, and when i do realm.add(a) b also gets updated in the db and it's fetched from api – Godfather Nov 11 '16 at 07:16
  • You can check if `b` already exists in the database by testing `b.realm != nil`. Setting `a.b = b` would be the same as `realm.add(b, update: false)` if it doesn't already exist in the database, so you need to keep that in mind. – TiM Nov 11 '16 at 18:39
  • I have a similar issue. http://stackoverflow.com/questions/40592350/realm-cant-create-object-with-existing-primary-key-value. Please help – Deekshith Bellare Nov 14 '16 at 15:36