Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating Object overriding non modified nested object #6059

Closed
MangeshMurhe opened this issue Jan 11, 2019 · 3 comments
Closed

Updating Object overriding non modified nested object #6059

MangeshMurhe opened this issue Jan 11, 2019 · 3 comments

Comments

@MangeshMurhe
Copy link

MangeshMurhe commented Jan 11, 2019

Goals

Updating object should not override non modified properties/inner objects.

I have user object and it's nested object as follows:

class User: Object {
    @objc dynamic var id = ""
    @objc dynamic var name: String = ""
    @objc dynamic var age: Int = 0
    @objc dynamic var building: Building?
    var roles = List<Role>()
    
    override static func primaryKey() -> String? {
        return "id"
    }
}

class Role: Object {
    @objc dynamic var id = ""
    @objc dynamic var name = ""
    
    override static func primaryKey() -> String? {
        return "id"
    }
}

class Building: Object {
    @objc dynamic var id = ""
    @objc dynamic var name = ""
    @objc dynamic var street = ""
    
    override static func primaryKey() -> String? {
        return "id"
    }
}

When i update few properties from user object lets I want to update age from 25 to 5. but when i update only age the rest of properties from User object gets overriden.
In previous version of realm (2.10.0) it was working correctly. But it was not working properly in realm version 3.13.1

Expected Results

Before updating age, user object is :

User {
		id = d451cc00-8a8b-11e8-9217-1de4dfc59e03;
		name = Anubhav;
		age = 25;
		building = Building {
			id = a3253da0-8977-11e8-8b34-ed33d4403871;
			name = Sitara;
			street = Manatee Avenue East;
		};
		roles = RLMArray<Role> <0x600000118db0> (
			[0] Role {
				id = a3253da0-8977-11e8-8b34-ed33d4403871;
				name = Painter;
			},
			[1] Role {
				id = a3253da0-8977-11e8-8b34-ed33d4403871;
				name = Painter;
			},
			[2] Role {
				id = a3253da0-8977-11e8-8b34-ed33d4403871;
				name = Painter;
			}
		);
	}

After updating users age, object should be :

User {
		id = d451cc00-8a8b-11e8-9217-1de4dfc59e03;
		name = Anubhav;
		age = 5;
		building = Building {
			id = a3253da0-8977-11e8-8b34-ed33d4403871;
			name = Sitara;
			street = Manatee Avenue East;
		};
		roles = RLMArray<Role> <0x600000118db0> (
			[0] Role {
				id = a3253da0-8977-11e8-8b34-ed33d4403871;
				name = Painter;
			},
			[1] Role {
				id = a3253da0-8977-11e8-8b34-ed33d4403871;
				name = Painter;
			},
			[2] Role {
				id = a3253da0-8977-11e8-8b34-ed33d4403871;
				name = Painter;
			}
		);
	}

Actual Results

User {
		id = d451cc00-8a8b-11e8-9217-1de4dfc59e03;
		name = (null);
		age = 5;
		building = (null);
		roles = List<Role> <0x6000015682d0> (
		
		);
	}

Code Sample

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }
    
    @IBAction func test(sender: UIButton) {
        
        let dict: NSDictionary = ["id": "d451cc00-8a8b-11e8-9217-1de4dfc59e03",
                    "title": "Testing JSON",
                    "description": "Hi this is first pb",
                    "building": ["id": "a3253da0-8977-11e8-8b34-ed33d4403871",
                                 "name": "Sitara",
                                 "street": "Manatee Avenue East"
                                ]
                    ]

        print(Pinboard(dictionary: dict))
        
        let userDict: NSDictionary = ["id": "d451cc00-8a8b-11e8-9217-1de4dfc59e03",
                                  "name": "Anubhav",
                                  "age": 25,
                                  "roles": [["id": "a3253da0-8977-11e8-8b34-ed33d4403871",
                                            "name": "Worker"],
                                            ["id": "a3253da0-8977-11e8-8b34-ed33d4403871",
                                             "name": "Gardner"],
                                            ["id": "a3253da0-8977-11e8-8b34-ed33d4403871",
                                             "name": "Painter"]
                                            ],
                                  "building": ["id": "a3253da0-8977-11e8-8b34-ed33d4403871",
                                               "name": "Sitara",
                                               "street": "Manatee Avenue East"
                                                ]
            ]
        
        Realm.writeAsync(type: User.self, objectDictionary: userDict)
        
        let userDict2: NSDictionary = ["id": "d451cc00-8a8b-11e8-9217-1de4dfc59e03",
                                       "age": 5]
        
        Realm.writeAsync(type: User.self, objectDictionary: userDict2)
    }
}

extension Realm {
class func writeAsync<T: Object>(type: T.Type, objectDictionary: NSDictionary, update: Bool = true, errorHandler: @escaping (( error : Swift.Error) -> Void) = {  in return }, block: ((Realm, T) -> Void)? = nil) {
        DispatchQueue(label: "background").async {
            autoreleasepool {
                do {
                    let realm = try Realm(configuration: Realm.Configuration.defaultConfiguration)
                    try realm.write {
                        let object = T(json: objectDictionary.toJsonString())
                        realm.create(type, value: object, update: update)
                        
                        if let block = block {
                            block(realm, object)
                        }
                        let usrs = realm.objects(User.self)
                        print(usrs)
                    }
                } catch {
                    errorHandler(error)
                }
            }
        }
    }
}

Version of Realm and Tooling

Realm framework version: 3.13.1

EVReflection version : 5.7.0

Xcode version: 10.1

@tgoyne
Copy link
Member

tgoyne commented Jan 11, 2019

let object = T(json: objectDictionary.toJsonString())
realm.create(type, value: object, update: update)

Here you are creating a User object, and then asking Realm to create a managed copy of that object, overwriting the existing values if an object already exists with that primary key. Realm doesn't have any way to magically know that you only want some of the existing values overwritten by the values in that object and not others.

The solution to this is to pass the dictionary which only has the keys which you want updated directly to realm.create() rather than using the intermediate object which has no concept of a key not being present.

@tgoyne tgoyne closed this as completed Jan 11, 2019
@MangeshMurhe
Copy link
Author

Thanks tgoyne for quick reply. In previous realm version(2.10.0) it was working properly, but after i have updated realm version it was not working. So can you please tell me why the deviation has taken place.

@tgoyne
Copy link
Member

tgoyne commented Jan 15, 2019

This behavior has not changed since 1.0.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 15, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants