public class Board: Object {
let styles = List<Style>()
dynamic var id = ""
override public static func primaryKey() -> String? {
return "id"
}
}
public class Style: Object {
dynamic var id = ""
override public static func primaryKey() -> String? {
return "id"
}
}
I have some sync with Web API,
and the problem is that when I update style object, it will be added to the board twice:
let queryRecordID = realm.objects(Style).filter("id == '\(entry.id)'")
if queryRecordID.count == 0{
//First time adding
println("First time adding: \(entry.id)")
realm.add(entry, update: false)
board.styles.append(entry)
styles.append(entry)
}else{
//Updating
println("Updating: \(entry.id)")
realm.add(entry, update: true)
board.styles.append(entry)
If I remove board.styles.append(entry) from updating part, then object will lose this relationship.
Hi Dmitry!
If you call 'add(_:update:)' and your object doesn't already have a primary key set, then by calling that method, you'll be creating another entry object.
Does your code set a primary key value after you've created the first entry object?
@TimOliver Hi Tim, my code uses primary key value to update objects if they are already in database. Th e problem with existing code is that it erases relationship when updating the object.
I think I can change relationship to keep board property in each style, than it will be no problem with updating, but it looks a little bit odd for me.
Hrmm, okay. That's really confusing then. I'm wondering if this might actually be a bug.
Are you able to upload a sample app that we can test out on this end?
@TimOliver Sure. Just sent it to [email protected] with link on this issue. Thank a lot.
This is actually the intended behavior, not to say it's something that we can't look into making easier to use/understand.
I'd actually vote for everything but raw add or create doing an update under the hood if the object has a primary key, to simplify this scenario
I had proposed this a while back, but we decided against it, and closed the issue... it's somewhere in GitHub.
I have a similar problem. I have a model Person with a property dog: Dog? which is already initialized. After saving/updating the Person (including the Dog) the .dog property is nil using the following code:
realm.write {
self.realm.add(person, update: true)
}
Is there a workaround for this?
@schickling Thanks for the post! We determined this is the intended behavior of the add method in this case.
If you need to use add in this context, simply keeping a reference to the dog object, and re-assigning it to the dog property after the add method should work.
Thanks!
Could you please explain _why_ this is the intended behavior?
It's basically because in this instance, there's not enough information on the standalone object's side to safely know if the object is intentionally nil, or merely unset. As such, while it's not the most elegant solution, you as the developer need to make the decision on the behalf of the objects in this transaction.
Sorry this isn't more clear. I agree with the above sentiments that we need to make this look more obvious.
There should definitely be a comment about that in the docs. I've pulled my hair out over this behavior. :+1:
I think I have / had the same issue, here's my code:
public class Parent: Object, Equatable, Hashable {
private dynamic var _myChild: Child?
.....
public var MyChild: Child? {
get {
return _myChild
}
set {
guard let myChild = newValue else {
// newValue should be non nil
return
}
let realm = Realm()
do {
try realm.write {
realm.add(myChild, update: true)
_myChild = myChild // If this Line is missing, the relationship is lost after the update
}
}
catch let error as NSError {
...
}
}
}
Both Classes (Parent and Child) have a primary key and both keys are set (NSUUID as String). Now everything works fine, but if I update the child of the Parent using the Property "MyChild", the actual child value inside the Realm get麓s update, but the relationship to the Parent is lost. Therefore I had to add the Line "_myChild = myChild" directly after the update. I guess this is the same "wanted" behavior like the other examples above.
Isn't there any way to update the Child Property without manually restoring the relationship? This Behavior is really error prone and generates substantial overhead (This is a small Example, my 'real' classes have much more Properties / Code).
@TimOliver mentioned in his explanation that the object doesn't know if the child / relationship is intentionally nil, or merely unset. But what I don't understand: I never set the child Property to nil, so why get the relationship destroyed by the update?
I know this issue is pretty old, but because it's one of the first entries I've found on Google regarding this problem I'm gonna drop here my workaround:
https://gist.github.com/nakiostudio/76f58769461feac9fe9272dd4726f865
it would be great if the explanation could be added to the documentation.
Wow, yeah this issue is a blast from the past. Realm's definitely changed a huge degree since July of last year. :)
We updated the docs relatively recently to emphasise that since nil is now a valid value (Since nullability was added after this issue), you need to ensure that the values being passed to add(_, update:) are either complete Object instances, or in the case of a dictionary, only the properties that are to be changed, in order to ensure that otherwise valid data isn't NULL'd out.
That being said, I'm not sure if that docs point fully applies to this issue.
I just tried replicating this issue in the 'Simple' Realm Swift sample app running 0.102.0. I added a primary key to the Dog object, and after an instance was created and assigned as a relation of a Person object, I created a new one entirely from scratch, and then attempted to add it to the Realm using add(_, update:).
It worked fine for me. The original Dog object was updated with the new values from the new instance, and it still remained as a child object of the Person object. I'm not sure if this is a good or a bad thing, since it might mean the behaviour has changed over time, and if people are still experiencing it, there might be a specific use-case that's causing it.
So, just to confirm, is anyone still getting this is Realm 0.102.0, and if so, what are you doing exactly (i.e., in terms of what type of objects/data are you passing to add(_, update:))?
Yeah I still got this, that why I arrived here on this topic. But I don't create my object in a traditional way, I use ObjectMapper. I have a User with Photos. When I refresh the user, (but the web service doesn't provide me the photos because it's a separate web service), I do : let user = Mapper<User>().map(item.rawString())! and then I save it with try! Realm().write { Realm().add(user, update: true) } and all the properties not contained in the web service are niled out. I guess to check if the problem come from ObjectMapper, I have to try let user = User() and manual mapping for everything
I confirm that with manual mapping, it's still nil out all defined properties after update. If this is the intended behavior, then it's really disappointing because people can build an object phase by phase, and don't expect to have to start from scratch when they need to update one field of the object.
I tried with create(_, update:) instead of add(_, update:) and the behavior is perfect : the object is partially updated and non-defined properties are not niled out. In my opinion, add should have the same behavior to avoid confusion. It's a bit strange that "create" update partially and "add" update destructively
Most helpful comment
I tried with
create(_, update:)instead ofadd(_, update:)and the behavior is perfect : the object is partially updated and non-defined properties are not niled out. In my opinion, add should have the same behavior to avoid confusion. It's a bit strange that "create" update partially and "add" update destructively