Can't set link to existing managed embedded object

We are getting an error attempting to use an embedded object twice - within the same object.

Can’t set link to existing managed embedded object

So here’s a quick example

class PersonClass: Object {
   @objc dynamic var name = ""
   @obc dynamic var default_address: EmbeddedAddress!
   let addressList = List<EmbeddedAddress>()
}

class EmbeddedAddress: EmbeddedObject {
   @objc dynamic var state = ""
}

A person class, with no addresses, is created and written to realm

We then want to update the person by adding an address to the address list and then setting one of them as the default address

let addr = EmbeddedAddress()
addr.state = "Florida"

let jay = realm.objects(PersonClass.self).filter("name == 'Jay'").first!
try! realm.write {
   jay.addressList.append(addr)
   jay.default_address = addr
}

and then running throws an error

Can’t set link to existing managed embedded object

Likewise, if we change the write around to populate the default_address first

try! realm.write {
   jay.default_address = addr
   jay.addressList.append(addr)
}

Cannot add an existing managed embedded object to a List

Is this expected behavior?

Yes, this is expected - embedded objects can only have one parent - for a non-intuitive definition of “parent”. In your case, it may seem like the parent is the same, but the property path is also considered part of the parent information. To try and give you an analogy - top-level objects are serialized to json with their ids (that can be either the primary key or an internal id). Embedded objects are serialized in their entirety. So if you have the following structure:

{
  "name": "jay",
  "default_address": {
    "city":"some city"
  },
  "addresses": [
    {
      "city":"some city"
    }
  ]
}

Even though default_address and addresses[0] contain the same information, they can’t inherently be regarded as the same object. In that sense, they are similar to complex value types at least when it comes to persistence. We were considering automatically creating a copy of the object if you tried to assign it to a property, but decided against it because we thought it wouldn’t be obvious to a developer that those are now different objects.

2 Likes

@nirinchev

Interesting - thanks for the very clear explanation.

It would be great if the docs were updated to more clearly state what you answer states as it really makes it obvious these are discreet objects that cannot be referenced. And the bit about the “parent” object not actually being the parent object due to the path constraints is really good info.

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.