How to load data in the background without running into incorrect thread exception later on

Hi all,

The realm documentation states that we don’t have to worry about threads and everything is nice an simple. There it states that the most efficient thing would be to let the UI bind directly to the Realm objects. They also implement INotifyPropertyChanged.

I must be getting something fundamentally wrong because it appears as all loading must then be happening on the UI thread, i.e. no background loading, no progress bars or spinning wheels are possible. The UI freezes until the work is done.

If I attempt to move the load into a Task or other background scenario, I ultimately end up in the exception ‘System.Exception: Realm accessed from incorrect thread.’ when the UI is reading a nested object. I understand that the root object belongs to the worker thread and the lazy loading can only succeed from there.

My only two conclusions:

  1. If I wanted to use background loading, I must not use Realm Objects on the UI due its thread affinity.
  2. To avoid any trouble with threads, stop using Realm objects at all outside of the data tier.

Please tell me, I am wrong :slight_smile:

Can you post some sample code illustrating the issues you’re facing? It’s difficult to make suggestions without seeing what is going wrong. Generally speaking though, when working on a background thread, you should re-open the Realm on that thread, perform any updates to it, then close it. Any changes made in the background will then raise change notifications on the UI thread and the UI can update itself. But again, it would be a lot easier if there was some code illustrating the problematic behavior which we can discuss.

1 Like

Example simplified pseudo code:

public class SomeRepository 
{
  Task LoadAll() 
  {
            IEnumerable<T> result = null;
            await Task.Run(() =>
            {
                Thread.Sleep(2000); // Just to make it a bit longer
                var realm = Realm.GetInstance();
                result = realm.All<T>().ToArray();
            });
 
           // Any attempt outside of the action to access or map a nested object is resulting in the thread exception
          // That is because the RealmObjects were loaded in the background task
            Console.WriteLine(result.First().NestedObject.ToString()); 
  }
}

// Any attempt outside of the action to access or map a nested object is resulting in the thread exception
// That is because the RealmObjects were loaded in the background task

Your comment is correct. In Realm, objects are thread-confined so you can’t access a referenced object across multiple threads in that way.

Also, by looking at your example you may be using a repository patter. We generally discourage that as it makes Realm’s live objects not that valuable anymore.

Anyway, back to your question. To achieve what you want you can use a ThreadsafeReference. Like so

var tsr = await Task.Run(() =>
{
    using var realm = Realm.GetInstance();
    var foos = realm.All<Foo>();
    // Do something with foos
    return ThreadSafeReference.Create(foos);
});

var mainRealm = Realm.GetInstance();
var mainFoos = mainRealm.ResolveReference(tsr);

As another little piece of advice, we generally recommend the following:

  • if you’re on the main thread, open a singleton Realm instance and just data-bind models to the UI and rely on notifications
  • In the background threads, open a new realm instance, perform any updates, and then close the Realm.

Finally, a valuable resource for you to read could be the following https://docs.mongodb.com/realm/sdk/dotnet/advanced-guides/threading/ .

2 Likes

Thanks Andrea, you actually confirmed my (today’s) conclusions:

  1. The repository pattern causes here more trouble than it solves:

    • generic queries are already on the Realm or can extend the IQueryable type
    • Write operations on repositories could be violating ACID since not all writes would be in one transaction.
  2. I will use one realm for reading and showing data on the screen

  • In case reading noticeable takes time, I will use the ThreadSafeReference
  • In cases reading is fast, I won’t bother with tasks to embrace simplicity
  1. Write operations in a background thread will only use a short living realm (no repository pattern) -the UI realm shall get the updates based on notifications.
1 Like

Another nice article about Realm and Xamarin found here:

2 Likes

I’m glad I could help.
I agree with all you said in the short summary and about

In case reading noticeable takes time, I will use the ThreadSafeReference

I’d add that I doubt you’ll have the need for this. Of course, it depends what you need to achieve, but generally lazy loading helps a lot here.

1 Like

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