Search Results for

    LINQ support in Realm .NET

    To make a query with Realm, you use the Realm.All<T>() method to get an IQueryable<T> instance. On this you can then apply the operators listed below.

    Restriction Operators

    Where is supported. OfType is not but it would be redundant as a query in Realm will always consist of a collection of the class initially specified.

    Where takes a predicate. To see the supported operations for predicates in Realm queries, refer to the Predicate Operations section.

    Example:

    var oldDogs = realm.All<Dog>().Where(dog => dog.Age > 8);
    

    Ordering Operators

    OrderBy, OrderByDescending, Thenby, and ThenByDescending are all supported. Reverse is not yet supported. Currently, you can only order by persisted properties on the class that you are querying. This means that dogs.OrderBy(dog => dog.Owner.FirstName) and the like is not yet supported.

    Example:

    var contacts = realm.All<Person>().OrderBy(p => p.LastName).ThenBy(p => p.FirstName);
    

    Conversion Operators

    ToArray, ToList, ToDictionary, and ToLookup are all supported. Cast isn't, but it would be redundant as a query in Realm will always consist of a collection of the class initially specified.

    Example:

    var phoneBook = realm.All<Person>().ToDictionary(person => person.PhoneNumber);
    

    Element Operators

    All of the main element operators are supported:

    • First and FirstOrDefault
    • Last and LastOrDefault
    • Single and SingleOrDefault

    These methods take an optional predicate. To see the supported operations for predicates in Realm queries, refer to the Predicate Operations section.

    Access to a single element by an index is supported by ElementAt and ElementAtOrDefault.

    Note that, as is standard C# behaviour of default(T), the variants ...OrDefault return a single null RealmObject if there is no matching element.

    DefaultIfEmpty is not yet supported.

    Quantifiers

    Any is supported.

    All and Contains are not yet supported.

    Any takes an optional predicate. To see the supported operations for predicates in Realm queries, refer to the Predicate Operations section.

    Aggregate Operators

    Count is supported.

    LongCount, Sum, Min, Max, and Average are not yet supported.

    Count takes an optional predicate. To see the supported operations for predicates in Realm queries, refer to the Predicate Operations section.

    Predicate Operations

    As a general rule, you can only create predicates with conditions that rely on data in Realm. Imagine a class

    class Person : RealmObject
    {
        // Persisted properties
        public string FirstName { get; set; }
        public string LastName { get; set; }
    
        // Non-persisted property
        public string FullName => FirstName + " " + LastName;
    }
    

    Given this class, you can create queries with conditions that apply to the FirstName and LastName properties but not to the FullName property. Likewise, properties with the [Ignored] attribute cannot be used.

    Note that currently, the property must be the left side of a condition. This means that

    var oldDogs = realm.All<Dog>().Where(dog => 7 < dog.Age); // INVALID query, do not copy
    

    is illegal and would have to be changed into the equivalent

    var oldDogs = realm.All<Dog>().Where(dog => dog.Age > 7); // Fixed
    

    Relational Operators

    Equality operators can be applied to all property types: ==, !=

    Furthermore, the following can be used for numerical types: <, <=, >, >=

    String Operators

    With strings, you can use: Contains, StartsWith, and EndsWith, Equals, and Like.

    Example:

    var peopleWhoseNameBeginsWithJ = realm.All<Person>.Where(p => p.FirstName.StartsWith("J"));
    

    By default, Realm will perform a case-sensitive comparison, but you can provide StringComparison.OrdinalIgnoreCase argument to overwrite that. Since there is no overload for Contains that accepts StringComparison on older .NET frameworks, we've provided a helper method that can be used when querying:

    var peopleWhoseNameContainsA = realm.All<Person>().Where(p => QueryMethods.Contains(p.FirstName, "a", StringComparison.OrdinalIgnoreCase));
    

    The Like query method can be used to compare a string property against a pattern. ? and * are allowed as wildcard characters, where ? matches 1 character and * matches 0 or more characters:

    var words = realm.All<Word>().Where(p => QueryMethods.Like(p.Value, "?bc*"));
    
    // Matches abc, cbcde, but not bcd
    

    When not used in a query expression, Like falls back to using RegEx to enforce the same rules.

    Composition

    You can use parentheses and the || and && operators to compose queries.

    Example:

    var PuppyRexes = realm.All<Dog>().Where(dog => dog.Age < 2 && dog.Name == "Rex");
    

    A note on liveness

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

    realm.Write(() =>
    {
        realm.Add(new Person { FirstName = "John" });
        realm.Add(new Person { FirstName = "Peter" });
    });
    
    var js = realm.All<Person>().Where(p => p.FirstName.StartsWith("J"));
    
    foreach(var j in js)
    {
        Console.WriteLine(j.FirstName); // ==> John
    }
    
    realm.Write(() =>
    {
        realm.Add(new Person { FirstName = "Joe" });
    });
    
    foreach(var j in js)
    {
        Console.WriteLine(j.FirstName); // ==> John, Joe
    }
    

    This differs from the typical behavior of object/relational mappers (ORM's) where the result of a query is fetched and kept in memory as it was.

    However, 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. So imagine you have a query like this:

    var recentLogEntries = realm.All<LogEntry>().Where(l => l.TimeStamp > DateTime.Now.AddHours(-1));
    

    Here, the recentLogEntries variable will contain all the log entries that have a TimeStamp later than one hour before the time when the query was first run (via foreach, ToList etc.). Newly added log entries will be included on subsequent runs, but the time they are compared to will not be updated.

    Not yet supported

    The following features are not yet supported. A few of them will not be supported as the Realm architecture renders them unnecessary.

    Grouping Operators

    GroupBy is not supported.

    Set Operators

    Distinct, Union, Intersect, and Except are not supported.

    Partitioning Operators

    Take, Skip, TakeWhile, and SkipWhile are not yet supported.

    These are less important than when using an ORM. Given Realm's zero-copy pattern, data is only read from the database when the properties on the objects are accessed, so there is little overhead in simply iterating over a part of a result.

    Projection Operators

    Select and SelectMany are not yet supported.

    The select keyword used with the query syntax is supported as long as you select the RealmObject itself and not some derivative:

    var oldDogs = from d in realm.All<Dog>() where d.Age > 8 select d;
    

    Concatenation Operators

    Concat is not supported.

    Join Operators

    Join and GroupJoin are not supported.

    Note that joins are less vital when using Realm than when using a relational database and an ORM. Instead of using keys to identify relations, you simply refer to the related object.

    So given a class

    public class Address : RealmObject
    {
        public string StreetName { get; set; }
        public int Number { get; set; }
    }
    

    you can simply use that in another class like so:

    public class Customer : RealmObject
    {
        public string Name { get; set; }
        public Address Address { get; set; }
    }
    

    This works like an ordinary reference in C# which means that if two Customer instances are assigned the same Address object, changes to that address will apply to both customer objects.

    • Edit this page
    In this article
    Back to top Copyright © 2020-2024 Realm
    Generated by DocFX