Search code examples
c#xamarinxamarin.formsrealmobservablecollection

Realm + Xamarin Forms Update Query


I'm using Realm + Xamarin Forms to do what I figure is about the most basic operation possible: a list view shows a collection of items, with a search bar filtering the results as the user types.

I have a get only collection property used as the list view's items source, initially populated from a Realm query, and this gets updated automatically with any changes to data, but I can't figure out how to update the search text without adding a set and literally replacing the entire collection.

This is very inefficient--I assume this is triggering re-registration of a bunch of notify-changed event listeners for the collection and each item in it and generally causing mass chaos with each letter tapped.

In the past I've created my own wrapping observable collection with a search method to handle this and I suppose that is an option here as well, but is there any way to do this with Realm? That is, to update the query without recreating the entire collection, some way to re-run the original query?


Solution

  • Update: This technique not longer works.

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    ...it also differs from the behavior of LINQ to Objects, where every iteration will reevaluate expressions, meaning that changes to both sides of a condition will affect the result. A Realm query will evaluate the right-hand sides of the conditions on the first run.

    When you construct a query that contains Where parameters that are based upon non-Realm based conditions the query results do not update when those variable/parameters are changed unless you update/execute the query again.

    Realm queries are live, in the sense that they will continue to represent the current state of the database.

    So what I do is to create a filter class (RealmObject), then if you instance a "filter object", save it to Realm, you can base your Linq's Where parameters upon one or more of the "filter" properties. Updating this RealmObject filter via Realm.Add(filterObject, true) your queries based upon that object are also updated

    Realm queries are live, in the sense that they will continue to represent the current state of the database.

    The results are lighting fast filtering that works great in any UI Search routine.

    Example Model:

    public class ARealmClass : RealmObject
    {
        public int Key { get; set; }
        public string KeyString { get; set; }
    }
    
    public class ARealmClassFilter : RealmObject
    {
        [PrimaryKey]
        public int Key { get; set; }
        public int FilterKeyBy { get; set; }
    }
    

    Populate a Realm with some test data

    var realm = Realm.GetInstance();
    var all = realm.All<ARealmClass>();
    if (all.Count() == 0)
    {
        realm.Write(() =>
        {
            for (int i = 0; i < 1000; i++)
            {
                var obj = new ARealmClass { Key = i, KeyString = i.ToString() };
                realm.Add(obj);
            }
        });
    }
    

    Dynamic Live Query Example:

    var realm = Realm.GetInstance();
    var all = realm.All<ARealmClass>();
    Console.WriteLine(all.Count());
    var filterItem = new ARealmClassFilter { Key = 1, FilterKeyBy = 500 };
    realm.Write(() =>
    {
        realm.Add(filterItem);
    });
    var filtered = all.Where(_ => _.Key > filterItem.FilterKeyBy);
    Console.WriteLine(filtered.Count());
    realm.Write(() =>
    {
        filterItem.FilterKeyBy = 750;
        realm.Add(filterItem, true);
    });
    Console.WriteLine(filtered.Count());
    

    Output:

    2017-04-24 11:53:20.376 ios_build_foo[24496:3239020] 1000
    2017-04-24 11:53:20.423 ios_build_foo[24496:3239020] 499
    2017-04-24 11:53:20.425 ios_build_foo[24496:3239020] 249
    

    Note: Quoted text @ https://realm.io/docs/xamarin/latest/api/linqsupport.html