SomeStudent
SomeStudent

Reputation: 3048

Realm how to close and read

I am having an issue where I am encountering the following error: Realms.Exceptions.RealmClosedException when I try to read my list of realm objects after I retrieved them. The closing of realm is my desired behavior as in my logs I saw ~2K instances of crashes reporting Realm OOM exceptions so I decided to experiment with wrapping my call to realm in a using statement as so:

List<RealmDomain.User> users;

using(var realm = Realm.GetInstance(config))
{
    users = realm.All<RealmDomain.User>().ToList();
}

return users;

I then try to work with this data as follows (and that is when the exception is raised) allUsers.FirstOrDefault(x => x.PortalUserId == id.ToString());. allUsers in this case is the variable holding the data returned by the last block of code. Thus I am wondering what is the correct way to properly handle disposing of realm in order to ensure we don't run into OOM exceptions with it, and how to properly read the data from said source even after it has been closed?

Edit: The block which returns the users is inside of my UserRepository, the application implements the UnitOfWork pattern (to access our realm db) which is then accessed via DI.

Edit2: Another follow up question would be: should I only wrap my calls to realm in a Using statement if it's only a CUD operation (Create, Update, Delete) whilst reads should not be wrapped in that and let the GC handle disposing of the realm instance as needed later?

Upvotes: 1

Views: 771

Answers (1)

papafe
papafe

Reputation: 3070

I think that actually there are multiple points in your question.

Disposing

The way that you dispose your realm really depends on whether you are on the main thread or on a background thread.

If you are on a main thread then you should not dispose your realm, and it would make sense to either call Realm.GetInstance() when you need it, or to initialize the realm as a singleton, like in the following snippet:

public class MyViewModel
{
    private readonly Realm realm;

    public MyViewModel()
    {
        this.realm = Realm.GetInstance(); //or this.realm = RealmProvider.Singleton
    }
} 

If you are on a background thread then you definitely need to dispose of the realm. In this case the using statement is probably the easiest thing to do:

public async Task OnBackgroundThread()
{
    using(var realm = Realm.GetInstance()) //From C#8 you don't even need the braces
    {
        //do work with realm
    }
} 

You need to dispose of realm on background threads otherwise you will cause the increase of the size of the realm on the disk. You can read more about why in this answer.

ToList()

Using ToList() on realm.All() is probably not a good idea, as you will load all the objects in memory losing the "laziness" of access. If what you need to do is find a certain object you can use a query like:

realm.All<User>().Where(x => x.PortalUserId == id.ToString()).First();

Repository

Realm does not really work well with the repository pattern. If you really want to use the repository pattern, then you will lose some of the advantages of working with realm, like the fact that the objects and collections are live and auto-updating. Besides, this is all made even more complicated by the use of background threads because of what I have said before.

Upvotes: 4

Related Questions