RLMException attempting to create object with an existing primary key after check
Asked Answered
I

5

7

I'm receiving an RLMException for the following reason:

Attempting to create an object of type 'Student' with an existing primary key value '258975085-504336622-62850'.

The confusing part is that it's occurring just after a check that there are no existing objects with this key in the Realm.

let realm = try Realm()
if let info = realm.object(ofType: Student.self, forPrimaryKey: newStudent.userId) {
    try realm.write {
        info.name = newStudent.name
        info.school = newStudent.school
        info.email = newStudent.email
    }
}
else {
    try realm.write {
        realm.add(newStudent) //RLMException occurs here
    }
}

This code is all running asynchronously on the GCD utility queue, inside a do/catch block. It's triggered by a button in the user interface, but nothing else is accessing realm at the same time.

Why could that if statement allow the else code to run?

Intent answered 28/2, 2018 at 9:51 Comment(4)
why are you not writing userId to realm for new objects?Mosenthal
My userId is part of the Student object, so if it can find one with matching id then it doesn't need to write the id again, and it's included in the model if I'm creating a new object.Intent
did you try printing newStudent.userId's value? is it '258975085-504336622-62850'?Mosenthal
Yes, that's exactly what it was. I'm more confused by why it wouldn't be returned by the object call for that id at the startIntent
I
0

Answering my own question because I found the problem.

I think the problem was a previous app screen trying to save (the same) student object on a queue with Utility quality of service, meaning that it finished saving after the call to realm.object(...), but before the call to realm.add(...).

Moving the if statement inside the realm write transaction also helped (thanks EpicPandaForce).

Intent answered 28/2, 2018 at 10:39 Comment(1)
And that's why you should do the check IN the transaction instead of writing two different realm.write blocksSakovich
M
4
try! self.realm.write {
    self.realm.add(newStudent, update: true)
}

You're adding same Object (student) with existing primary key. So you can just update current one. Instead of deleting and adding new one.

Multiplicand answered 28/2, 2018 at 10:20 Comment(2)
But there are certain different fields that might already be saved. Would I not have to retrieve an object anyway to get those values rather than overwriting them?Intent
take a look here : #32891769Multiplicand
S
4

In my case, I added condition to check whenever new user logs in:

if newStudent == nil{
     self.realm.add(newStudent, update: .all)
}
Salt answered 18/3, 2020 at 11:10 Comment(0)
I
0

Answering my own question because I found the problem.

I think the problem was a previous app screen trying to save (the same) student object on a queue with Utility quality of service, meaning that it finished saving after the call to realm.object(...), but before the call to realm.add(...).

Moving the if statement inside the realm write transaction also helped (thanks EpicPandaForce).

Intent answered 28/2, 2018 at 10:39 Comment(1)
And that's why you should do the check IN the transaction instead of writing two different realm.write blocksSakovich
Q
0

2024 Update

setting UpdateModel in realm.create method does the trick.

realm.write(() => {
    realm.create(Entity, {...entity}, UpdateMode.Modified);
  });
Quaint answered 19/1, 2024 at 10:10 Comment(0)
T
0

Old Code

try! realm.write {
        realm.add(allPhotosListingData)
}

New Code with the fix

try! realm.write {
        realm.add(allPhotosListingData, update: .all)
}

This worked for me. Thanks for the help community.

Teresetereshkova answered 20/4, 2024 at 19:57 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.