Search code examples
c#.netmvvmuwprealm

Is it possible to use a RealmObject in a ViewModel, after disposing the Realm?


I'm considering switching from SQLite to Realm in my UWP applications, as Realm seems fairly easier to setup, but I'm having trouble with some limitations that so far are a deal-breaker for me, the most important one being that apparently you can't use realm objects after disposing the Realm instance that was used to retrieve them. So I wonder how am I supposed to load data to throw in a ViewModel, as after loading the data items that Realm instance would be gone.

Here's an example of a really basic ViewModel:

public class MyViewModel : ViewModelBase // Assume this has INotifyPropertyChanged setup
{
    private IEnumerable<MyItem> _Items;

    public IEnumerable<MyItem> Items
    {
        get => _Items;
        private set => Set(nameof(Items), ref _Items, value);
    }

    public async Task LoadDataAsync()
    {
        using (Realm realm = await Realm.GetInstanceAsync())
        {
            Items = realm.All<MyItem>().ToArray();
        }
    }
}

Assume that MyItem is some example model, which inherits from RealmObject.

Now, if I were using SQLite, I'd have no problems whatsoever there, as once retrieved from the database, each model instance would be a standalone object that I could just store in my ViewModel. Instead, classes that inherit from RealObject are linked to their original Realm instance, so if I try to use them (ie. read one of their properties) after the source Realm instance has been disposed, everything falls apart (I get a nice Exception).

The obvious workaround would be to keep two classes for each model: one that maps to the Realm database, and another one that's a standalone object. But this has some drawbacks:

  • Twice the number of classes
  • Additional work (and memory waste) to copy each instance to the standalone class
  • This just seems wrong, I mean, come on

Another possibility would be to keep a singleton instance of a Realm object that is never closed, but doesn't sound like a good idea either (and it would have problems when using multiple threads too, so it's definitely not a valid solution).

I've seen that the Java version of the Realm library has some "getRawObject" method (or something like that) that allows you to get a standalone copy of a RealmObject, but still, I guess this actually creates a copy of the model instance, so it doesn't sound good either.

My question is:

Is there a way to just get the same flexibility of SQLite, where once loaded, you can pass the models around anywhere you want (including to other threads), use them in ViewModels, and then also eventually edit them and pass them back around to the database to update them on disk?

Bonus point: as another example, consider a library that loads some items from a Realm database and return them to the user. Once loaded, those objects would be read-only, meaning that even if they somehow were modified, they wouldn't be changed on the database itself. My current solution is again to copy each loaded model into another classes that doesn't inherit from RealmObject, but as I said, this is not scalable at all (imagine a large project with dozens of models, it would be impossible to do so).


Solution

  • In .NET, it seems to be possible to detach the managed RealmObject from the Realm only if you create a copy of it some way or another.

    See https://stackoverflow.com/a/38061292/2413303

    public Contact ToStandalone()
    {
        return new Contact()
        {
            companyName = this.companyName,
            dateAdded = this.dateAdded,
            fullName = this.fullName,
            gender = this.gender,
            website = this.website
        };
    }
    

    Technically it doesn't have to be a different class, but it needs to be created with new.

    As for having to make a copy - well, that's what you always did with SQLite too.