Realm .NET SDK

repository·community·Indexed 23 days ago

https://github.com/realm/realm-dotnet

An embedded, object-oriented database for .NET/C# supporting iOS, Android, UWP, macOS, Linux, and Windows. It provides live objects, LINQ-based querying, and integration with Atlas App Services for data sync and authentication. The SDK supports frameworks such as .NET MAUI, Avalonia, and Unity.

Tokens
40K
Snippets
100
Records
205
Agent score
79%

What's inside realm-dotnet

  1. Core workflows with Realm .NET

    community

    The Realm SDK for .NET follows a standard object-oriented database workflow:

    1. Define an Object Schema: Use idiomatic C# classes to define the structure of your data.
    2. Configure & Open a Database: Initialize the database, which can include options like populating initial data or using an encryption key for security.
    3. Read and Write Data: Perform CRUD (Create, Read, Update, Delete) operations. You can query data using standard LINQ syntax or the Realm Query Language (RQL).
    4. React to Changes: Use change listeners on 'live objects' to automatically trigger UI updates or other logic when data changes.
  2. What is Realm Query Language (RQL)?

    community
    Realm Query Language (RQL) is a string-based query language used to constrain searches when retrieving objects from a Realm. It is based on NSPredicate syntax. Queries evaluate a predicate for every object in a collection; if the predicate resolves to true, the object is included in the results. You can use RQL in most Realm SDKs via filter or query methods, and also within Realm Studio for visual data browsing.
  3. Communicate Realm objects across threads

    community

    Since live objects are thread-confined, use these strategies to share data or react to changes across threads:

    • Modify an object on two threads: Query for the object independently on both threads.
    • React to changes: Use Realm's notification system.
    • See changes from other threads: Call Realm.Refresh() on your current thread's instance to advance to the most recent state.
    • Send fast, read-only views: Use Frozen Objects to create immutable snapshots that can be passed between threads.
    • Share many read-only views: Copy the object out of the Realm entirely.
  4. Understand Realm's MVCC architecture

    community

    Realm uses Multiversion Concurrency Control (MVCC) to provide safe, lock-free, and concurrent access.

    Key Concepts:

    • Atomic Commits: Transactions are atomic writes.
    • Versioning: Realm maintains multiple versions of the data history (similar to Git branches). However, unlike Git, Realm only has one 'true' latest version (the HEAD) that all writes converge upon.
    • Copy-on-Write: When changes are made, Realm copies the relevant parts of its B+ tree structure. This ensures isolation and durability; if a write fails, the original version remains untouched.
    • Zero-Copy: Realm uses memory mapping to allow reading values directly from disk, which is the basis for its 'live' object behavior.
  5. Define and use Sets in Realm .NET

    community

    A Realm set is an implementation of ISet<TValue>, ICollection<TValue>, and IEnumerable<TValue>. It functions similarly to a C# HashSet<T>.

    Key Rules:

    • Supported Types: You can use any Realm-supported type except for other collections.
    • Declaration: Define a set using a getter-only ISet<TValue> property.
    • Nullability:
      • Objects: Deleting an object from the database automatically removes it from any sets. Therefore, a set of objects will never contain null objects.
      • Primitives: Sets of primitive types can contain null values if using nullable types (e.g., ISet<double?>). To disallow nulls, use non-nullable types (e.g., ISet<double>).
      • Required Attribute: If using the older RealmObject base class or if nullability is not enabled, use the [Required] attribute for sets containing nullable reference types like string or byte[] to ensure they are not null.
    public partial class Inventory : IRealmObject
    {
        // A Set can contain any Realm-supported type, including
        // objects that inherit from RealmObject
        public ISet<Plant> PlantSet { get; }
    
        public ISet<double> DoubleSet { get; }
    
        public ISet<int?> NullableIntsSet { get; }
    
        public ISet<string> RequiredStrings { get; }
    }
  6. Determine property nullability in Realm .NET

    community

    The Realm .NET SDK uses C# nullability annotations (?) to determine if a property is required or optional.

    • Required Properties: Properties that are not marked as nullable (e.g., int, string, byte[]) are treated as required by Realm.
    • Optional Properties: Properties marked with ? (e.g., int?, string?) are treated as optional.

    Rules for Realm Object Types

    • Realm Objects: Properties that are other Realm object types must be declared as nullable (e.g., public Dog? MyDog { get; set; }).
    • Collections: You cannot declare collections (like IList, ISet, IDictionary, or IQueryable backlinks) as nullable themselves. However, the types inside the collections follow specific rules:
      • Primitives: Can be required or nullable (e.g., IList<int> or IList<int?>).
      • Realm Objects in Lists/Sets/Backlinks: The parameter type cannot be nullable (e.g., IList<Dog> is valid, but IList<Dog?> is a compile-time error).
      • Realm Objects in Dictionaries: If the dictionary value is a Realm object, you must declare the value type parameter as nullable (e.g., IDictionary<string, Dog?>).

    Legacy/Non-Nullable Contexts

    If you are using the older RealmObject base class or have nullability disabled in your project, you must use the [Required] attribute to mark string and byte[] properties as required.

    #nullable enable
    public partial class Person : IRealmObject
    {
        /* Reference Types */
        public string NonNullableName { get; set; } // Required
        public string? NullableName { get; set; }    // Optional
    
        /* Value Types */
        public int NonNullableInt { get; set; }      // Required
        public int? NullableInt { get; set; }        // Optional
    
        /* Realm Objects */
        public Dog? NullableDog { get; set; }        // Must be nullable
    
        /* Collections of Primitives */
        public IList<int> IntListWithNonNullableValues { get; }
        public IList<int?> IntListWithNullableValues { get; }
    
        /* Collections of Realm Objects */
        public IList<Dog> ListOfNonNullableObjects { get; } // Valid
        // public IList<Dog?> ListOfNullableObjects { get; } // Compile-time error
    
        public IDictionary<string, Dog?> DictionaryOfNullableObjects { get; } // Must be nullable for Realm objects
    
        [Backlink(nameof(Dog.Person))]
        public IQueryable<Dog> MyDogs { get; }
    }
  7. Define and use Dictionaries in Realm .NET

    community

    A Realm dictionary is an implementation of IDictionary<string, TValue> where the key must be a string. The value TValue can be any Realm-supported type except for collections.

    To define a dictionary in your model, use a getter-only IDictionary<string, TValue> property.

    Key Constraints:

    • Keys must be of type string.
    • Realm disallows the use of . or $ characters in map keys. If you need to use these characters, you must use percent encoding/decoding to store them.

    Nullability:

    • Dictionaries of objects can contain null objects.
    • Dictionaries of primitive types can contain null values if using nullable types (e.g., IDictionary<string, double?>).
    • To disallow null values, use non-nullable types (e.g., IDictionary<string, double>).
    • If you are using the older RealmObject base class or do not have nullability enabled, use the [Required] attribute for nullable reference types like string or byte[] to ensure they are treated as required.
    public partial class Inventory : IRealmObject
    {
        [PrimaryKey]
        [MapTo("_id")]
        public string Id { get; set; }
        
        // Value can be objects inheriting from RealmObject or EmbeddedObject
        public IDictionary<string, Plant?> Plants { get; }
    
        public IDictionary<string, bool> BooleansDictionary { get; }
    
        public IDictionary<string, int?> NullableIntDictionary { get; }
    
        public IDictionary<string, string> RequiredStringsDictionary { get; }
    }
  8. Understand Schema Versions and Migrations

    community

    A migration transforms an existing Realm and its objects from a current schema version to a newer one. This is necessary when your IRealmObject classes change (e.g., adding, deleting, or modifying properties).

    Key Concepts

    • Schema Version: An integer that identifies the state of a Realm Schema. If not specified, it defaults to 0.
    • Version Progression: Migrations must always update a realm to a higher schema version. Realm will throw an error if you attempt to open a realm with a version lower than its current version, or if the version is the same but the schema differs.
    • Automatic vs. Manual: Simple changes like adding a property are handled automatically by Realm, but data transformation (like splitting a name or converting a type) requires a manual MigrationCallback.
  9. How data binding works with Realm in .NET

    community

    In .NET frameworks like Xamarin, MAUI, and Avalonia UI, Realm objects and collections are 'live,' meaning they automatically reflect data changes. This is achieved through standard .NET interfaces:

    • Realm objects implement INotifyPropertyChanged.
    • Realm collections implement INotifyCollectionChanged.

    When you bind these live objects or collections to your UI, both the UI and the underlying Realm data stay in sync automatically.

    NOTE: The Realm SDK does not support Compiled Bindings.

  10. Understand Geospatial Data Types in .NET SDK

    community

    The Realm .NET SDK supports geospatial queries using four primary data types: GeoPoint, GeoCircle, GeoBox, and GeoPolygon. These types allow you to perform queries such as finding objects within a specific radius or shape.

    Important Limitation: You cannot persist these geospatial data types directly in your Realm models. They are intended exclusively as arguments for geospatial queries. To persist location data, you must use a GeoJSON-compatible structure (see Persisting GeoPoint Data).

  11. Use mixed collections with RealmValue

    community

    Starting in version 12.2.0, RealmValue can hold collections of RealmValue elements, allowing you to model highly unstructured data.

    Capabilities:

    • Supports nesting mixed collections up to 100 levels deep.
    • Supports List<RealmValue> and Dictionary<string, RealmValue>.
    • You can query mixed collection properties and register listeners for changes.
    • You can find and update individual elements within the mixed collection.

    Limitations:

    • You cannot store Set types or Embedded Objects within mixed collections.
  12. Perform a chaining delete for dependent objects

    community

    Realm does not automatically delete dependent (child) objects when a parent object is deleted. If you do not manually delete them, they will remain as orphaned objects in the Realm. To perform a chaining delete, you must iterate through the dependencies and delete them using RemoveRange or Remove before deleting the parent object.

    realm.Write(() =>
    {
        // Remove all of Ali's dogs.
        realm.RemoveRange(ali.Dogs);
    
        // Remove Ali.
        realm.Remove(ali);
    });