In writing the app for Patient-Reported Outcomes in Parkinson's Disease (http://www.propd.org), I needed a more robust persistence service. At the same time, I stumbled upon Realm who develops an Open Source Mobile Database and Mobile Platform. In February 2017 Realm released an SDK for .NET and Xamarin. Realm looked to be robust and scalable, features I require for another project. I decided to use Realm for my PRO-PD project. You can find the code (https://github.com/rsatter/PRO-PD) for PRO-PD on GitHub. I released the source code under Apache license.
Calling Realm a Mobile Database underplays Realm's real power as a container, not just a database. Adding a Realm server turns it into a distributed container. How one thinks of Realm as a persistence layer or as a container impacts the implementation of an app.
Using Realm strictly as a persistence layer might be the quickest to implement. It keeps the object model and architectural layers intact. A set of Realm objects is created for example RealmOrder. Then a Realm service implementation is built or modify the existing service. The add Order could validate the Order before opening a transaction. Then the Order is copied into a realm version of the Order object. I would suggest something like new RealmOrder(order).
Realm realm = Realm.GetInstance();
using (Transaction _transaction = realm.BeginWrite())
{
realm.Add(new RealmOrder(order));
_transaction.Commit();
}
The container option may require refactoring classes and application logic. The approach of using Realm as a container is best when building new apps. With Realm, you can think of your solution as a problem domain, modeled by domain objects, and the UIs as windows into the problem domain. Think of Realm as a container for the problem domain. The persistence of state between sessions is just one feature of Realm's container management. To get a better understanding of problem domain and architecture, I recommend reading about Clean Architecture design. For a great post on the subject, check out The Clean Architecture (https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html) by Uncle Bob. This excellent article on software architecture had me rethink my approach to software.
If you look at the code for PRO-PD, the app is composed of three main parts Services, Models and UseCases, and the UI in the form of Views and ViewModels. Services as a single service called ContainerService managing Realm and DryIoc. The Models and UseCases contain domain objects survey, patient, and report. It then has use case objects that manipulate the domain objects. Finally, the UI is composed of Views and simple ViewModels that are only responsible for managing a single view. Due to Realm and DryIoc, I could easily port the App to the Web, Tablets, wearables, and pcs. I only need to create View and ViewModel implementations. The problem domain code does not change. To get the data to the researchers, I just need to set up a Realm server and turn on synchronization. The passing around the objects is transparent to the app.
The core of the app is the SurveyUseCase. This object is just the algorithm for having the user answer the questions of the survey. When the use case runs, it first executes startup code.
realm = ContainerService.GetInstance();
// Load survey or create survey if it is not already in the DB
survey = realm.All<Survey>().FirstOrDefault() ?? LoadSurvey();
transaction = realm.BeginWrite();
patient = realm.All<Patient>().FirstOrDefault() ?? new Patient();
if (!patient.IsManaged)
{
realm.Add(patient);
}
report = patient.AddReport();
In the above code, the Realm SDK seems to have little impact. Query for the survey. If not found then load it into Realm. Start a transaction for since Realm supports ACID. Then start creating and updating the objects of the problem domain. Once the use case completes, the transaction is either committed or rolled back. To enable an object to interact with Realm it needs to be inherited from RealmObject.
There are a few issues. The first is related to Realm use of Fody (https://github.com/Fody/Fody). Fody is an Open Source project that allows for code injection into your compiled code. Rather than insert boilerplate code everywhere, Fody injects it for you post compilation. PostSharp is the oldest tool that does this. The classic example is OnPropertyChanged, my ViewModel classes littered with SetProperty and a field as the backing store.
public bool IsBusy
{
get => isBusy;
set => SetProperty(ref isBusy, value);
}
The Models do not need any thanks to Fody. I need to have Fody do the same to my ViewModels!
The issue is Fody needs an XML file included in the projects. Unfortunately, Nuget no longer allows content injection. Thus you need to create the FodyWeavers.xml file and add it to projects that need it.
<?xml version="1.0" encoding="utf-8" ?>
<Weavers>
<RealmWeaver />
</Weavers>
The other issue related to Fody is AppCenter blows up trying to build the Android and iOS projects. I kept getting cannot find RealmWeavers. A big thank you to Shawn Dyas in AppCenter support for finding a solution.
<PropertyGroup>
<SolutionDir>..\</SolutionDir>
</PropertyGroup>
Conclusion Realm is a very powerful object database with a beautiful object-oriented SDK. I cannot wait to get my hands on the Realm Cloud.