Search code examples
c#xamarinrealm

Updated RealmObject when read via Backlink is null


I'm updating an object & then accessing it via Backlink. It has not worked yet.

class Person : RealmObject
{
    [PrimaryKey]
    public int Id { get; set; }

    public string Name { get; set; }

    public IList<Dog> Dogs { get; }
}

class Dog : RealmObject
{
    [PrimaryKey]
    public int Id { get; set; }

    [Ignored]
    public Person Person
    {
        get                 
        {
            if (_person == null)
                _person = Persons.First();

            return _person;
        }
    }  

    [Backlink(nameof(Person.Dogs))]
    public IQueryable<Person> Persons { get; }
}

Add:

var dog = new Dog () {Id = 1};
var person1 = new Person () {Id = 1, Name = "Person1"};
person1.Dogs.Add(dog);
realm.Write(() => realm.Add(person1));

Update:

var person11 = new Person() {Id = 1, Name = "Person11"};
realm.Write(() => realm.Add(person11, true));

Read:

var readPerson11 = realm.All<Dog>.First().Person;

I get an exception on the Person property.

Unhandled Exception:

System.InvalidOperationException: Sequence contains no matching element occurred.

(If readPerson11 is read without updating it, then I get back the person11 properly.)

I've tried realm.Refresh() after updating & before reading Person. Also tried GetBacklinks<Person>(nameof(Person.Dogs)) with no result.

Help will be highly appreciated.


Solution

  • The reason is that the update overrides all values of the Person object. If you check, after the update, person11.Dogs will be empty. So when updating, you need to supply the entire collection of dogs assigned to this person. One way to do it would be to use the old values:

    var currentPerson11 = realm.Find<Person>(1);
    var person11 = new Person() {Id = 1, Name = "Person11"};
    foreach (var dog in currentPerson11.Dogs)
    {
        person11.Dogs.Add(dog);
    }
    realm.Write(() => realm.Add(person11, true));
    

    Alternatively, you can invert the relationship - rather than have a list of Dogs assigned to a person and backlinks on the dog object, you can have a Person property on the Dog class and backlinks on Person:

    public class Person : RealmObject
    {
        // ... other props
    
        [Backlink(nameof(Dog.Person))]
        public IQueryable<Dog> Dogs { get; }
    }
    
    public class Dog : RealmObject
    {
        // ... other props
    
        public Person Person { get; set; }
    }
    

    Then updating the person will not affect their Dogs collection.