Realm Xamarin enables you to efficiently write your app’s model layer in a safe, persisted and fast way. Here’s what it looks like:

// Define your models like regular C# classes
public class Dog : RealmObject 
{
    public string Name { get; set; }
    public int Age { get; set; }
    public Person Owner { get; set; }
}

public class Person : RealmObject 
{
    public string Name { get; set; }
    public RealmList<Dog> Dogs { get; } 
}

var realm = Realm.GetInstance();

// Use LINQ to query
var puppies = realm.All<Dog>().Where(d => d.Age < 2);

puppies.Count(); // => 0 because no dogs have been added yet

// Update and persist objects with a thread-safe transaction
realm.Write(() => 
{
    var mydog = realm.CreateObject<Dog>();
    mydog.Name = "Rex";
    mydog.Age = 1;
});

// Queries are updated in realtime
puppies.Count(); // => 1

// LINQ query syntax works as well
var oldDogs = from d in realm.All<Dog>() where d.Age > 8 select d;

// Query and update from any thread
new Thread(() =>
{
    var realm2 = Realm.GetInstance();

    var theDog = realm2.All<Dog>().Where(d => d.Age == 1).First();
    realm2.Write(() => theDog.Age = 3);
}).Start();

Getting Started

You install Realm via NuGet, or you can browse the source code on GitHub.

Prerequisites

We support the following environments:

  • Visual Studio 2015 or higher, or Xamarin Studio version 6.00.0 or higher.
  • Xamarin iOS version 9.6.2.4 for iOS 7 or higher, using native UI or Xamarin Forms.
  • Xamarin Android version 6.0.4.0 for API level 10 or later, using native UI or Xamarin Forms.
  • Xamarin.Mac is not yet supported.

Important note for PCL users - this works via the NuGet Bait and Switch Trick. You have to install the Realm NuGet package into every PCL that uses Realm as well as each of your platform-specific projects, e.g.: your final app for iOS and Android. If you are using shared projects, you only have to install the NuGet into each platform-specific project.

Installation

  1. On the “Packages” node under your project in the Solution pane, click the gear button and select “Add Packages…”
  2. Type “Realm” in the search box
  3. Select Realm and add it
  4. You should see Fody added as a dependency in turn.

The Realm package contains everything you need to use Realm. It depends on Fody weaver, responsible for turning your RealmObject subclasses into persisted ones.

At this point, you should have the package installed. If your project was already using Fody you will see an update to your existing FodyWeavers.xml. The important thing is that you end up with a FodyWeavers.xml file that contains all the weavers you want active, including RealmWeaver.

This is an example of how your FodyWeavers.xml file should look if you were not already using any other weavers when you added Realm:

<?xml version="1.0" encoding="utf-8" ?>
<Weavers>
    <RealmWeaver />
</Weavers>
  1. In your project, choose Tools - NuGet Package Manager - Manage Packages for Solution…
  2. Select the Realm package in the list of available packages
  3. Check that your project is checked on the right hand side, so the Install button is enabled
  4. Press Install
  5. Press OK in the dialog that comes up, which should be telling you it will install Realm and Fody

The Realm package contains everything you need to use Realm. It depends on Fody weaver, responsible for turning your RealmObject subclasses into persisted ones.

At this point, you should have the package installed. If your project was already using Fody you will see an update to your existing FodyWeavers.xml. The important thing is that you end up with a FodyWeavers.xml file that contains all the weavers you want active, including RealmWeaver.

This is an example of how your FodyWeavers.xml file should look if you were not already using any other weavers when you added Realm:

<?xml version="1.0" encoding="utf-8" ?>
<Weavers>
    <RealmWeaver />
</Weavers>

Realm Browser

We also provide a standalone Mac app named Realm Browser to read and edit .realm files.

Realm Browser

You can generate a test database with sample data using the menu item Tools > Generate demo database.

If you need help finding your app’s Realm file, check this StackOverflow answer for detailed instructions.

The Realm Browser is available on the Mac App Store.

API Reference

You can consult our full API reference for all classes, methods & more.

Examples

You can find a number of examples in our repository in the examples folder.

Getting Help

  • Need help with your code? Ask on StackOverflow. We actively monitor & answer questions on SO!
  • Have a bug to report? Open an issue on our repo. If possible, include the version of Realm, as much logging output as possible, the Realm file, and a project that shows the issue.
  • Have a feature request? Open an issue on our repo. Tell us what the feature should do, and why you want the feature.

Models

Realm data models are defined using traditional C# classes with properties. Simply subclass RealmObject to create your Realm data model objects.

Realm model objects mostly function like any other C# objects – you can add your own methods and events to them and use them like you would any other object. The main restrictions are that you can only use an object on the thread which it was created, and persisted properties have generated getters and setters.

Relationships and nested data structures are modeled simply by including properties of the target type or RealmList for typed lists of objects.

// Dog model
public class Dog : RealmObject 
{
    public string Name { get; set; }
    public int Age { get; set; }
    public Person Owner { get; set; }
}

public class Person : RealmObject 
{
    public string Name { get; set; }
    public RealmList<Dog> Dogs { get; } 
}

Supported Types

Realm supports primitive types except unsigned ones (bool, char, byte, short, int, long, float and double) as well as string, and DateTimeOffset. The nullable equivalents are supported as well.

Relationships

RealmObjects can be linked to each other by using RealmObject and RealmList properties.

RealmLists implement the standard .NET IList generic interface.

To-One Relationships

For many-to-one or one-to-one relationships, simply declare a property with the type of your RealmObject subclass.

public class Dog : RealmObject 
{
    // ... other property declarations
    public Person Owner { get; set; };
}

public class Person : RealmObject{}

You can use this property like you would any other:

var jim = realm.CreateObject<Person>()
var rex = realm.CreateObject<Dog>();
rex.Name = "Rex";
rex.Owner = jim;

To break the relationship, simply assign null:

rex.Owner = null;

When using RealmObject properties, you can access nested properties using normal property syntax. For example rex.Owner.Address.Country will traverse the object graph and automatically fetch each object from Realm as needed.

To-Many Relationships

You can define a to-many relationship using RealmList properties. When you use these properties, you get back a RealmList which may be empty or contains related RealmObjects of a single type.

To add a “Dogs” property on our Person model that links to multiple dogs, we simply declare it as a RealmList<Dog> property.

public class Dog : RealmObject
{
}

public class Person : RealmObject 
{
    // ... other property declarations
    public RealmList<Dog> Dogs { get; } 
}

You can access and assign RealmList properties as usual for an IList:

jim.Dogs.Add(rex);
Assert(jim.Dogs.Count == 1);  // nobody but rex

Optional Properties

Reference types such as string and related RealmObject values can be null.

Nullable value types such as int? are fully supported.

Controlling Property Persistence

Classes which descend from RealmObject are processed by the Fody weaver at compilation time. All their properties that have automatic setters and getters are presumed to be persistent and have setters and getters generated to map them to the internal Realm storage.

We also provide some C# attributes to add metadata to control persistence.

To avoid a property being made persistent, simply add the [Ignored] attribute. A common example is using external media, where you could persist the path to a file but not the binary image:

public string HeadshotPath { get; set; }

// Image in memory during run
[Ignored]
public Image Headshot { get; set; }

Custom Setters

Properties which have their own setter or getter implementation are automatically ignored. You can use this to add validation:

private string Email_ { get; set; }

// Validating version of persistent Email_ property
public string Email
{
    get { return Email_; }
    set
    {
        if (!value.Contains("@")) throw new Exception("Invalid email address");
        Email_ = value;
    }
}

Indexed Properties

Currently only strings, integers, booleans and DateTimeOffset can be indexed.

Indexing a property will greatly speed up queries where the property is compared for equality (i.e. the == and Contains operators), at the cost of slower insertions.

To index a property, simply add the [Indexed] attribute to the property declaration, e.g.:

public class Person : RealmObject 
{
    [Indexed]
    public string Name { get; set; }
    public RealmList<Dog> Dogs { get; } 
}

Auto-Updating Objects

RealmObject instances are live, auto-updating views into the underlying data, which means objects never have to be refreshed. Modifying the properties of an object will immediately reflect in any other instances referring to the same object.

Dog myDog;
realm.Write(() => 
{
    var mydog = realm.CreateObject<Dog>();
    mydog.Name = "Fido";
    mydog.Age = 1;
});

var myPuppy =  = realm.All<Dog>().First(d => d.Age == 1);
realm.Write(() => 
{
  myPuppy.age = 2
}

Console.WriteLine($"age of my dog: {myDog.age}") // => 2

This aspect of RealmObject not only keeps Realm fast and efficient, it allows your code to be simpler and more reactive. For example, if your UI code is dependent on a specifc Realm object, you don’t need to worry about refreshing or re-fetching it before triggering a UI redraw.

You can subscribe to Realm notifications to know when Realm data in an object is updated, indicating when your app’s UI should be refreshed.

ObjectId Attributes

A single [ObjectId] attribute can be specified on one property to set the model’s object id. Declaring an object id allows objects to be looked up and updated efficiently and enforces uniqueness for each value.

Only chars, integral types, and strings can be used as object ids.

Once an object with an ObjectId is added to a Realm, the object id cannot be changed.

If you come from a traditional database background, you can think of the object id as being very similar to a SQL primary key.

From an object modelling perspective, the object id is like a persistent pointer to an object. You can use the object id to quickly lookup the object to get a reference to it in a different thread.

Note that putting the [ObjectId] attribute on multiple properties is undefined behavior, and may cause runtime errors or just use one of the attributed properties.

public class Person : RealmObject 
{
    [ObjectId]
    public string SSN { get; set; }
    [Indexed]
    public string Name { get; set; }
    public RealmList<Dog> Dogs { get; } 
}

Ignored Properties

Use the [Ignored] attribute to leave a property alone and just treat it as a standard C# property.

If you define a setter or getter function on the property then it is automatically ignored.

Model Inheritance

Realm Xamarin does not allow models to be further subclassed in any way. The CreateObject generic method only works if you use it for a class which descends directly from RealmObject.

Collections

Realm has two types that help represent groups of objects, which we refer to as “Realm Collections”:

  1. RealmResults, a class representing objects retrieved from queries.
  2. RealmList, a class representing to-many relationships in models.

Both conform to the IEnumerable interface which supports lazy enumeration - the size of the collection is known but objects are only loaded into memory as you iterate the collection.

Writes

All changes to an object (addition, modification and deletion) must be done within a write transaction.

To share objects between threads or re-use them between app launches, you must persist them to a Realm, an operation which must be done within a write transaction.

Since write transactions incur non-negligible overhead, you should architect your code to minimize the number of write transactions.

Because write transactions could potentially fail like any other disk IO operations, you should be prepared to handle exceptions from writes so you can handle and recover from failures like running out of disk space. There are no other recoverable errors. For brevity, our code samples don’t handle these errors but you certainly should in your production applications.

There are two easy ways to create write transactions: Realm.BeginWrite() and Realm.Write(). The first one, Realm.BeginWrite() returns a Transaction which implements the Dispose pattern, allowing you to use it with using:

using(var transaction = realm.BeginWrite()) 
{
    person.FirstName = "John";
    person.Age = 56;
    transaction.Commit();
}

Note that you must explicitly Commit the transaction, or it will automatically be rolled back. The other way is to wrap your mutating code with Realm.Write():

realm.Write(() => 
{
    person.FirstName = "John";
    person.Age = 56;
});

Here, the implicit transaction will be committed by default unless an exception was thrown.

Creating Objects

When you have defined a model you can instantiate your RealmObject subclass and add the new instance to the Realm. Consider this simple model:

public class Dog : RealmObject 
{
    public string Name { get; set; }
    public int Age { get; set; }
}

You create an instance by calling the Realm.CreateObject<>() method:

realm.Write(() =>
{
    var mydog = realm.CreateObject<Dog>();  // immmediately managed by the Realm
    mydog.Name = "Rex";
    myDog.Age = 10;
});

After you have created the object, all changes you make to it will be persisted (and must be made within a write transaction). Any changes are made available to other threads that use the same Realm when the write transaction is committed.

Please note that writes block each other, and will block the thread they are made on if multiple writes are in progress. This is similar to other persistence solutions and we recommend that you use the usual best-practices for this situation, namely offloading your writes to a separate thread.

Due to Realm’s MVCC architecture, reads are not blocked while a write transaction is open. Unless you need to make simultaneous writes from many threads at once, you should favor larger write transactions that do more work over many fine-grained write transactions.

Updating Objects

You can update any object by setting its properties within a write transaction.

// Update an object with a transaction
using (var trans = realm.BeginWrite()) 
{
  author.Name = "Thomas Pynchon";
  trans.Commit();
}

Deleting Objects

Pass the object to be deleted to the Realm.Remove method within a write transaction.

var cheeseBook = realm.All<Book>().First(b => b.Name == "Cheese");

// Delete an object with a transaction
using (var trans = realm.BeginWrite()) 
{
  realm.Remove(cheeseBook);
  trans.Commit();
}

You can also delete all objects stored in a Realm. Note the Realm file will maintain its size on disk to efficiently reuse that space for future objects.

Queries

Queries implement standard LINQ syntax.

You get a basic, typed collection of all objects of a given type using the All method and then apply Where or other LINQ operators to get a filtered collection.

Fluent or Extension Syntax

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

Query Expression Syntax

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

Regardless of which syntax you use, the resulting RealmResults collection conforms to the IQueryable interface so you can further iterate or process it:

foreach (var d in oldDogs) 
{
  Debug.WriteLine(d.Name);
}

More Query Examples

If you’re not used to LINQ queries, here are some examples of basic queries to get you used to the syntax. Sticking with the Extension Syntax, you can see how to write your basic queries.

To extract a list of all users named John or Peter you would write:

var johnsAndPeters = realm.All<Person>().Where(p => 
    p.FirstName == "John" || 
    p.FirstName == "Peter");
var peopleList = johnsAndPeters.ToList();

The first statement gives you a new instance johnsAndPeters of the class RealmResults. It is an IQueryable created to find the users with the name “John” or “Peter”. This is standard LINQ implementation - you get an object representing the query. The query doesn’t do anything until you make a further call that needs to iterate or count the results.

The ToList call, in this example, fires off the query which maps straight to the Realm core.

Objects are not copied - you get a list of references to the matching objects, and you work directly with the original objects that match your query.

Instead of retrieving them all into a list, you could also iterate through the query results, with the standard C# foreach statement:

int i = 0;
foreach (var pers in johnsAndPeters) {        // iterate query
    Assert.That(peopleList[i++], Is.EqualTo(pers));  // check iterator against earlier list 
}

Logical Operators

The standard C# logical operators are used in LINQ expressions to compose the query.

That includes the ability to use parentheses to group nested expressions, with the precedence as you’d expect in an if statement:

var ComplexPeople = realm.All<Person>().Where(p => 
    p.LastName == "Doe" &&
    (p.FirstName == "Fred" || p.Score > 35));

Retrieving objects by type

To get all objects of a given type from a Realm, just use realm.All<T>(). It returns a RealmResults of all instances of the model class being queried - Person in the example above.

You can then choose to apply a LINQ query further to restrict the set. Remember, until you start iterating a RealmResults, there’s no overhead.

var ap = realm.All<Person> ();  // this is all items of a type
var scorers = ap.Where(p => p.Score > 35);  // restrict with first search clause
var scorerDoe = scorers.Where(p => p.LastName == "Doe");  // effectively an AND clause

Sorting

The standard LINQ clauses OrderBy, OrderByDescending, ThenBy, and ThenByDescending can be used to specify a multi-level sort that affects the order of objects supplied by a RealmResults.

They work via the internal query engine to provide efficient sorted access without loading all objects in the results. You don’t have to perform a query with Where to be able to use a sort - you can just sort the results from All.

Warning: If you use the ToList clause to extract a list of objects and then use an OrderBy you are sorting in-memory using LINQ for Objects. Make sure you only use ToList at the end of your expression.

var highestScore = realm.All<Person>().OrderByDescending(p => p.Score).First();

// sorting by two clauses and THEN using ToList to compare in an assertion
// (from a unit test that has duplicate first names)
var sortAD = realm.All<Person>().Where(p => p.IsInteresting).
    OrderBy(p => p.FirstName).
    ThenByDescending(p => p.Latitude).ToList();
var sortADname = sortAD.Select(p => p.FirstName);
Assert.That(sortADname, Is.EqualTo( new [] {"John", "John", "Peter"}) );

Chaining Queries

Since results are never copied, but are computed on request, you can very efficiently chain queries to gradually filter your data:

var teenagers = realm.All<Person>().Where(p => p.Age >= 13 && p.Age <= 20);
var firstJohn = teenagers.Where(p => p.FirstName == "John").First();

Limiting Results

Most other database technologies provide the ability to ‘paginate’ results from queries (such as the LIMIT keyword in SQLite). This is often done out of necessity to avoid reading too much from disk, or pulling too many results into memory at once.

Since queries in Realm are lazy, performing this sort of paginating behavior isn’t necessary at all, as Realm will only load objects from the results of the query once they are explicitly accessed.

If for UI-related or other implementation reasons you require a specific subset of objects from a query, it’s as simple as taking the RealmResults object, and reading out only the objects you need.

While you may be tempted to use the LINQ Take, that is not yet supported. When added, it will enumerate and instantiate all the objects you request in one operation.

Realms

Realms are our equivalent of a database: they contain different kinds of objects, and map to one file on disk.

The Default Realm

You may have noticed so far that we have always initialized our realm variable by calling Realm.GetInstance(string optionalPath). This static constructor will return a Realm instance for your thread, that maps to a file called default.realm located in Environment.SpecialFolder.Personal.

It is important to note that Realm instances are thread singletons, meaning that the static constructor will return the same instance for every thread.

Configuring a Realm

Calling Realm.getInstance(filename) makes it easy to get started with Realm. For more fine-grained control, it is possible to create a RealmConfiguration object that controls more aspects of how a Realm is created.

A RealmConfiguration allows you to control the database path in several ways. (Note that you can’t change the path once the configuration has been constructed.) You can:

  1. Change the entire path by passing in a new absolute path.
  2. Put your Realm files in a subdirectory of the standard location by passing in a relative path.
  3. Change the Realm filename by just passing in a new filename.

You can pass around an instance of a configuration, to open all your Realms with the same settings. This is the most common use for opening the same Realm in different threads.

You can also override the default configuration to change the defaults without having to pass around an object.

Closing Realm Instances

Realm implements IDisposable in order to take care of native memory deallocation and file descriptors so instances will be closed automatically when variables go out of scope.

You can safely call Realm.Close() at any time, including multiple times, to ensure early closing.

Finding a Realm File

If you need help finding your app’s Realm file, check this StackOverflow answer for detailed instructions.

Auxiliary Realm Files

Alongside the standard .realm files, Realm also generates and maintains additional files for its own internal operations.

  • .realm.lock - A lock file for resource locks.
  • .realm.log_a, .realm.log_b - Log files for transaction logs.
  • .realm.note - A named pipe for notifications.

These files don’t have any effect on .realm database files, and won’t cause any erroneous behavior if their parent database file is deleted or replaced.

When reporting Realm issues, please be sure to include these auxiliary files along with your main .realm file as they contain useful information for debugging purposes.

Bundling Realm Files

If you want to bundle a Realm with your app, see this great StackOverflow Answer which explains how to include files in Xamarin projects as resources and copy them for use.

Class Subsets

In some scenarios you may wish to limit which classes can be stored in a specific Realm.

You can do this by setting the ObjectClasses property of your RealmConfiguration:

class LoneClass : RealmObject
{
    public string Name { get; set;}
}

var config = new RealmConfiguration("RealmWithOneClass.realm");
config.ObjectClasses = new Type[] {typeof(LoneClass)};

// or specifying two classes in the Realm
config.ObjectClasses = new Type[] {typeof(Dog), typeof(Cat)};

Deleting Realm Files

In some cases, such as clearing caches, or resetting your entire dataset, it may be appropriate to completely delete a Realm file from disk.

Unlike most files, Realm files are memory-mapped and Realm instances expect the files to be available for the duration of the instance’s lifetime.

To avoid your application code having to be aware of all files in a Realm, we provide a convenience method Realm.DeleteRealm(RealmConfiguration).

var config = new RealmConfiguration("FileWeThrowAway.realm");
Realm.DeleteRealm(config); 
var freshRealm = Realm.GetInstance(config);

Threading

Within individual threads, you can just treat everything as regular objects without worrying about concurrency or multithreading. There is no need for any locks or resource coordination to access them (even if they are simultaneously being modified on other threads) and it is only modifying operations that have to be wrapped in transactions.

Realm makes concurrent usage easy by ensuring that each thread always has a consistent view of the Realm. You can have any number of threads working on the same Realms in parallel, and since they all have their own snapshots, they will never cause each other to see inconsistent state.

The only thing you have to be aware of is that you cannot have multiple threads sharing the same instances of Realm objects. If multiple threads need to access the same objects, they will each need to get their own instances (otherwise changes happening on one thread could cause other threads to see incomplete or inconsistent data).

Seeing Changes From Other Threads

On the main UI thread (or any thread with a runloop/looper), objects will automatically update with changes from other threads between each iteration of the runloop. At any other time you will be working on the snapshot, so individual methods always see a consistent view and never have to worry about what happens on other threads.

When you initially open a Realm on a thread, its state will be based off the most recent successful write commit, and it will remain on that version until refreshed. Realms are automatically refreshed at the start of every runloop iteration. If a thread has no runloop (which is generally the case in a background thread), then Realm.Refresh() must be called manually in order to advance the transaction to the most recent state.

Realms are also refreshed when write transactions are committed with Transaction.Commit().

Failing to refresh Realms on a regular basis could lead to some transaction versions becoming “pinned”, preventing Realm from reusing the disk space used by that version, leading to larger file sizes. Refer to our Current Limitations for more details on this effect.

Passing Instances Across Threads

Persisted instances of Realm, RealmObject, RealmResults, or RealmList can only be used on the thread on which they were created, otherwise an exception is thrown. This is one way Realm enforces transaction version isolation. Otherwise, it would be impossible to determine what should be done when an object is passed between threads at different transaction versions, with a potentially extensive relationship graph.

Instead, there are several ways to represent instances in ways that can be safely passed between threads. For example, an object with an ObjectId can be represented by its object id’s value; or a Realm can be represented by its RealmConfiguration. The target thread can then re-fetch the Realm or RealmObject using its thread-safe representation. Keep in mind that re-fetching will retrieve an instance at the version of the target thread, which may differ from the originating thread.

Using a Realm Across Threads

To access the same Realm file from different threads, you must initialize a new Realm to get a different instance for every thread of your app. As long as you specify the same configuration, all Realm instances will map to the same file on disk.

Sharing Realm instances across threads is not supported.
Realm instances accessing the same realm file must also all use the same RealmConfiguration.

Realm can be very efficient when writing large amounts of data by batching together multiple writes within a single transaction. Realm objects are not thread-safe and cannot be shared across threads, so you must get a Realm instance in each thread/dispatch_queue in which you want to read or write.

Notifications

On Android, change listeners only work on Looper threads. For non-looper threads, you manually have to use Realm.Refresh() instead.

If you have a background thread adding data to a Realm, your UI or other threads can get notified of changes in a Realm by adding a listener, which is executed when the Realm is changed (by another thread or process):

realm.RealmChanged += () => 
{
    // Update UI
}

Migrations

When working with any database, it is likely your data model will change over time. Since data models in Realm are defined as standard C# classes, making model changes is as easy as changing any other class.

Realm will automatically perform migrations that can be done without processing, like adding and removing classes or adding and removing properties from a class. For more complex changes, a proper migration is required. We do not yet have an API for this, but it is planned and will be added soon.

Encryption

Please take note of the Export Compliance section of our LICENSE, as it places restrictions against the usage of Realm if you are located in countries with an export restriction or embargo from the United States.

Realm supports encrypting the database file on disk with AES-256+SHA2 by supplying a 64-byte encryption key when creating a Realm.

var config = new RealmConfiguration("Mine.realm");
config.EncryptionKey = new byte[64] // key MUST be exactly this size
{
  0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
  0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
  0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
  0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
  0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
  0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
  0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
  0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78
};

var realm = Realm.GetInstance(config);  // will create/open encrypted realm "Mine.realm"

This makes it so that all of the data stored on disk is transparently encrypted and decrypted with AES-256 as needed, and verified with a SHA-2 HMAC. The same encryption key must be supplied every time you obtain a Realm instance.

You should use a key that is unique to your app, not the one in the example above. Furthermore, if you need unique keys for each user, look into the Xamarin.Auth API.

Note that if you specify the wrong key or fail to specify a key for an encrypted Realm, you get a RealmFileAccessErrorException when you call GetInstance.

There is a small performance hit (typically less than 10% slower) when using encrypted Realms.

Current Limitations

Realm is currently in beta and we are continuously adding features and fixing issues while working towards a 1.0 release. Until then, we’ve compiled a list of our most commonly hit limitations.

Please refer to our GitHub issues for a more comprehensive list of known issues.

Features missing from this preview version which are expected to be added prior to release:

  • Assigning list values to RealmList fields to add multiple relationships in one go
  • Async queries
  • Binary data fields (e.g., storing pictures)
  • Cascading deletes
  • Collection notifications
  • Default values – the standard way of defining them is not compatible with the weaving
  • Delete all objects
  • Dynamic Realms
  • IList used for declaration rather than requiring RealmList
  • Migrations
  • More LINQ operations
  • Searching by related data
  • Updating Objects by their ObjectId

General Limits

Realm aims to strike a balance between flexibility and performance. In order to accomplish this goal, realistic limits are imposed on various aspects of storing information in a realm. For example:

  1. Class names must be between 0 and 57 bytes in length. UTF-8 characters are supported. An exception will be thrown at your app’s initialization if this limit is exceeded.
  2. Property names must be between 0 and 63 bytes in length. UTF-8 characters are supported. An exception will be thrown at your app’s initialization if this limit is exceeded.
  3. iOS Limitation: The total size of all open Realm files cannot be larger than the amount of memory your application would be allowed to map in iOS — this changes per device, and depends on how fragmented the memory space is at that point in time (there is a radar open about this issue: rdar://17119975). If you need to store more data, you can split into multiple Realm files, and open and close them as needed.

File size & tracking of intermediate versions

You should expect a Realm database to take less space on disk than an equivalent SQLite database. If your Realm file is much larger than you expect, it may be because you have a RealmObject that is referring to an older version of the data in the database.

In order to give you a consistent view of your data, Realm only updates the active version accessed at the start of a run loop iteration. This means that if you read some data from the Realm and then block the thread on a long-running operation while writing to the Realm on other threads, the version is never updated and Realm has to hold on to intermediate versions of the data which you may not actually need, resulting in the file size growing with each write. The extra space will eventually be reused by future writes.

FAQ

General

Should I use Realm in production applications?

Realm has been used in production in commercial products since 2012. The Xamarin C# product has been in beta since December 2015, but uses the same C++ core as all other Realm products.

You should expect our C# APIs to change as we evolve the product from community feedback — and you should expect more features & bugfixes to come along as well.

Do I have to pay to use Realm?

No, Realm is entirely free to use, even in commercial projects.

How do you all plan on making money?

We’re actually already generating revenue selling enterprise products and services around our technology. If you need more than what is currently in our releases or in realm-dotnet, we’re always happy to chat by email. Otherwise, we are committed to developing realm-dotnet in the open, and to keep it free and open-source under the Apache 2.0 license.

I see references to a “core” in the code, what is that?

The core is referring to our internal C++ storage engine. It is not currently open-source but we do plan on open-sourcing it also under the Apache 2.0 license once we’ve had a chance to clean it, rename it, and finalize major features inside of it.

I see a network call to Mixpanel when I run my app, what is that?

Realm collects anonymous analytics when you run the Realm assembly weaver on your assemblies containing RealmObject classes. This is completely anonymous and helps us improve the product by flagging which version of Realm you use and what OS you use, and what we can deprecate support for. This call does not run when your app is in production, or running on your user’s devices — only when your assemblies are woven by Fody during build. You can see exactly how & what we collect, as well as the rationale for it in our source code.

Does Realm work as a Portable (PCL) Library?

You need to use the iOS or Android version of Realm with your executable but we offer a PCL that you can use to compile against the Realm API with. This is the NuGet Bait and Switch Trick in action. If you add Realm to a PCL project via NuGet, and also add it to your executable, it will work.

Troubleshooting

Crash Reporting

We encourage you to use a crash reporter in your application. Many Realm operations could potentially fail at runtime (like any other disk IO), so collecting crash reports from your application will help identify areas where either you (or us) can improve error handling and fix crashing bugs.

Most commercial crash reporters have the option of collecting logs. We strongly encourage you to enable this feature. Realm logs metadata information (but no user data) when throwing exceptions and in irrecoverable situations, and these messages can help debug when things go wrong.

Reporting Realm Issues

If you’ve found an issue with Realm, please either file an issue on GitHub or email us at help@realm.io with as much information as possible for us to understand and reproduce your issue.

The following information is very useful to us:

  1. Goals.
  2. Expected results.
  3. Actual results.
  4. Steps to reproduce.
  5. Code sample that highlights the issue (full Xamarin projects that we can compile ourselves are ideal).
  6. Version of Realm, OS X or Windows & Xamarin/Visual Studio.
  7. Xcode if targeting iOS, NDK if targeting Android.
  8. Platform, OS version & architecture on which the bug happens (e.g., 64-bit iOS 8.1).
  9. Crash logs & stack traces. See Crash Reporting above for details.

Realm Core Binary Fails to Download

When building Realm, part of the process includes downloading the core library as a static binary and integrating it into the Realm project. This is part of the wrappers building by Makefile.

It’s been reported that in certain instances, the core binary fails to download with the following error:

Downloading core failed. Please try again once you have an Internet connection.

This error can occur due to any of the following reasons:

  1. Your IP address range is from a region that is on the list of United States embargoes. In order to comply with U.S. law, Realm has not been made available in that region. For more information, please see our license.
  2. You are located in mainland China, and due to the country-wide firewall you are not able to properly access CloudFlare or Amazon AWS S3 services at the moment. Please see this issue on one of our other products for more information.
  3. Amazon AWS S3 could be experiencing service issues. Please check the AWS Service Health Dashboard and try again later.

Failing to Weave

You may see a warning in the build log about classes not having been woven. This indicates that the Fody weaving package is not properly installed.

Firstly, check that the FodyWeavers.xml file contains an entry for RealmWeaver.

The installation will copy RealmWeaver.Fody.dll up into a Tools directly in your solution directory (this is usually a sibling to your project directories). It is not linked into any of the projects but needs to be in that location for Fody to find the DLL.

It is also possible that the installation of Fody has failed. This has been experienced with Visual Studio 2015 and versions of NuGet Package Manager prior to version 3.2. To diagnose this, use a text editor to check that your .csproj has a line importing Fody.targets, such as:

<Import Project="..\packages\Fody.1.29.3\build\portable-net+sl+win+wpa+wp\Fody.targets"
    Condition="Exists('..\packages\Fody.1.29.3\build\portable-net+sl+win+wpa+wp\Fody.targets')" />

Simply upgrading to a later version of NuGet Package Manager should fix this problem.