vicdelfant
vicdelfant

Reputation: 23

Waiting for Realm writes to be completed

We are using Realm in a Xamarin app and have some issues refreshing the local database based on a remote source. Data is fetched from a remote endpoint and stored locally using Realm for easier/faster access.

Program flow is as follows:

  1. Fetch data from remote source (if possible).
  2. Loop through the entities returned by the remote source while keeping track of the IDs we've seen so far. New or updated entities are written to Realm.
  3. Loop through the set of locally stored entities, removing entities we haven't seen in step 2 with Realm.Remove(entity); (in a transaction)
  4. Return Realm.All<Entity>();

Unfortunately, the entities are returned by step 4 before all "remove" operations have been written. As a result, it takes a couple of refreshes before the local database is completely in sync.

The remove operation is done as follows:

foreach (Entity entity in realm.All<Entity>())
{
    if (seenIds.Contains(entity.Id))
    {
        continue;
    }

    realm.Write(() => {
        realm.Remove(entity);
    });
}

Is there a way to have Realm wait till the transaction is completed, before returning the Realm.All<Entity>();?

Upvotes: 2

Views: 1542

Answers (1)

Andy Dent
Andy Dent

Reputation: 17969

I am pretty sure this is not particularly a Realm issue - the same pattern would cause problems with a lot of enumerable, mutable containers. You are removing items from a list whilst iterating it so enumeration is moving on too far.

There is no buffering on Realm transactions so I guarantee it is not about have Realm wait till the transaction is completed but is your list logic.

There are two basic ways to do this differently:

  1. Use ToList to get a list of all objects from the All - this is expensive if many objects because you will instantiate all the objects.
  2. Instead of removing objects inside the loop, add them to a list of items to be removed then iterate that list.

Note that using a transaction per-remove, as you are doing with Write here is relatively slow. You can do many operations in one transaction.

We are also working on other improvements to the Realm API that might give a more efficient way of handling this. It would be very helpful to know the relative data sizes - the number of removals vs records in the loop. We love getting sample data and schemas (can send privately to [email protected]).

an example of option 2:

var toDelete = new List<Entity>();
foreach (Entity entity in realm.All<Entity>())
{
    if (!seenIds.Contains(entity.Id))
        toDelete.Add(entity);
}
realm.Write(() => {
    foreach (Entity entity in toDelete))
        realm.Remove(entity);
});

Upvotes: 1

Related Questions