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

LinkingObject property doesn't notify correctly #7493

Closed
ericjordanmossman opened this issue Oct 20, 2021 · 6 comments · Fixed by realm/realm-core#6074
Closed

LinkingObject property doesn't notify correctly #7493

ericjordanmossman opened this issue Oct 20, 2021 · 6 comments · Fixed by realm/realm-core#6074
Labels

Comments

@ericjordanmossman
Copy link
Contributor

ericjordanmossman commented Oct 20, 2021

How frequently does the bug occur?

All the time

Description

It appears that a linkingObject property doesn't notify properly when the origin property is on the same class
Write transactions where only a backlink property is changed does not notify.

This happens even without a keyPath parameter.

Screen Shot 2021-10-20 at 4 25 02 PM

Expected behavior is to receive a notification on a linkingObject property. Similar to how testBacklinkPropertyKeyPathNotifications4 behaves.

Stacktrace & log output

No response

Can you reproduce the bug?

Yes, always

Reproduction Steps

Example reproduction code

Version

10.17

What SDK flavour are you using?

Local Database only

Are you using encryption?

No, not using encryption

Platform OS and version(s)

All

Build environment

Xcode version: 13.0
Dependency manager and version: SPM

@ericjordanmossman
Copy link
Contributor Author

The issue is not strictly related to origin table and target table having the same table key. The below passes:

    func testBacklinkPropertyKeyPathToSameClass() {
        var parent: ModernAllTypesObject!
        var child: ModernAllTypesObject!

        let realm = try! Realm()
        try! realm.write {
            child = realm.create(ModernAllTypesObject.self)
        }
        let ex1 = expectation(description: "linking object notification")
        let token1 = child.observe(keyPaths: ["linkingObjects"]) { _ in
            ex1.fulfill()
        }

        try! realm.write {
            parent = realm.create(ModernAllTypesObject.self)
            parent.objectCol = child
        }

        waitForExpectations(timeout: 2, handler: nil)
        token1.invalidate()
    }

But this does not:

    func testBacklinkPropertyKeyPathToSameClass() {
        var parent: ModernAllTypesObject!
        var child: ModernAllTypesObject!

        let realm = try! Realm()
        try! realm.write {
            child = realm.create(ModernAllTypesObject.self)
        }
        let ex1 = expectation(description: "linking object notification")
        let token1 = child.observe(keyPaths: ["linkingObjects"]) { _ in
            ex1.fulfill()
        }
        try! realm.write {
            parent = realm.create(ModernAllTypesObject.self)
        }
        try! realm.write {
            parent.objectCol = child
        }

        waitForExpectations(timeout: 2, handler: nil)
        token1.invalidate()
    }

backlink_count is 0, then 1 (How I think it's expected). Though I'm still trying to figure out why the column isn't making it to change callback.

@ericjordanmossman
Copy link
Contributor Author

So the fact both the parent and child objects are of the same class is irrelevant. This is reproducible when target and origin properties are on different classes.

The actual issue is when reassigning the "objectCol", and by extension changing the "linkingObjects", is in a write transaction by itself.
A transaction like:

try! realm.write {
            parent.objectCol = child
}

would create a transaction log that's parsed with a "instr_set" case. The instr_set case only adds modifications to the changeset.

BUT linkingObject changes are delivered as insertions. So the insertion is never added to the callback.

In a write transaction like:

try! realm.write {
            parent = realm.create(ModernAllTypesObject.self)
            parent.objectCol = child
}

the transaction will also have a "instr_createObject" case because of the new object. Both the insertion for the new object, and the insertion representing the change to the "linkingObject" property are then added to the changeset.

@ericjordanmossman
Copy link
Contributor Author

This can be reproduce in core alone. So I'll get that and open an issue in core. Because I'm not sure if the solution is changing the transact_log or how we classify changes to a linkingObject property.

@ericjordanmossman ericjordanmossman changed the title LinkingObject property doesn't notify when referring to same object class LinkingObject property doesn't notify without another insertion in write transaction. Oct 22, 2021
@ericjordanmossman ericjordanmossman changed the title LinkingObject property doesn't notify without another insertion in write transaction. LinkingObject property doesn't notify correctly Oct 22, 2021
@connor-ricks
Copy link

I've attached an example that uses valuePublisher that shows a short example of this issue happening. Hopefully it helps.

Example.zip

@connor-ricks
Copy link

Any updates on this issue?

@aehlke
Copy link

aehlke commented Oct 1, 2022

Would be nice to have a scary disclaimer about this in the docs for LinkingObject if this is going to remain an issue

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
3 participants