DroidOS
DroidOS

Reputation: 8890

How to persist referenced RealmObjects

Consider the following RealmObject subclasses

public class TimeSlot extends RealmObject
{
 @PrimaryKey
 private int value = 0;
 private int hits = 0;

 @LinkingObjects("ats") private final RealmResults<Visit> visits = null;

 public TimeSlot(){}

 public TimeSlot(int time)
 {
  super();
  value = time;
 } 

  ...
}

public class Visit extends RealmObject
{
 private RealmList<TimeSlot> timeslots = null;

 public Visit()
 {
  super();
  timeslots = new RealmList<TimeSlot>();
 }

 public void addTimeSlot(TimeSlot ts) throws Exception
 {
  this.timeslots.add(ts);
  try
  {
   myRealm.beginTransaction();
   myRealm.copyToRealmOrUpdate(this,ImportFlag.valueOf("CheckSameValuesBeforeSet"));
   myRealm.commitTransaction();
  }
  catch(Exception e)
  {
   myRealm.cancelTransaction();
   throw e;
  }  
 } 
}  

Somewhere else in my code I do the following

myVisit.addTimeSlot(new TimeSlot(30));

to add a new TimeSlot to an existing instance of a Visit object, myVisit. You will note that in addTimeSlot I am copying the modified Visit instance to Realm. My question - doing so will also persist the freshly created TimeSlot object?

A related issue - when I retrieve myVisit from Realm is there a guarantee that the TimeSlot objects in myVisit.timeslots will be in the same order as when I added them?

Upvotes: 1

Views: 82

Answers (1)

Chris Shaw
Chris Shaw

Reputation: 1610

Most of your questions are answered in the Realm docs, if you know where to look. A lot of these questions are hinted at in the main docs, and then you need to find the correct API page. And sometimes resort to just trying it.

You will note that in addTimeSlot I am copying the modified Visit instance to Realm. My question - doing so will also persist the freshly created TimeSlot object?

That is correct. The docs for copyToRealmOrUpdate state: "This is a deep copy or update i.e., all referenced objects will be either copied or updated."

You've introduced a potential problem though. Your first line of addTimeSlot immediately amends the Visit object. This is fine in the case of either the Visit object being unmanaged, or if you have started a Realm transaction outside the call to addTimeSlot. But if this is not the case then you will receive an exception regarding 'Attempting to modify object outside of a write transaction'. Your method relies on you always operating on the unmanaged version of the object, and manually copying each change back to the Realm. This isn't really the recommended approach, as you're introducing the possibility of objects being out of sync. Better to always deal with managed objects.

You are also accessing a variable called myRealm, which I assume is a global reference to your Realm. Note that in the case of a managed object, you can access the getRealm() function to retrieve the realm for the object and avoid globals/passing parameters.

So, better is to:-

  1. Add the Visit to the Realm when you create it
  2. In addTimeSlot, use the result of getRealm() to verify it the Visit is managed. If so, add the TimeSlot to the Realm and the RealmList.

I'm interested how your TimeSlot primary key works though.

Anyway, back to your questions.

when I retrieve myVisit from Realm is there a guarantee that the TimeSlot objects in myVisit.timeslots will be in the same order as when I added them?

Yes. A RealmList is ordered. You can add elements either to the end or by inserting with a RealmList. This would obviously be redundant if the order was not stored. See the docs.

The docs mention that unmanaged objects are like simple POJOs. From what I understand if I create a RealObject subclass instance and never bother copying it to a Realm it will stay "unmanaged".

Correct.

But then what happens if I add it to a RealmList instance that is part of a "managed" RealmObject?

This is discussed here. Your list is then a managed realm list, and this statement applies:

It is possible to add unmanaged objects to a RealmList that is already managed. In that case the object will transparently be copied to Realm using Realm.copyToRealm(RealmModel, ImportFlag...) or Realm.copyToRealmOrUpdate(RealmModel, ImportFlag...) if it has a primary key.

Note though that your existing reference to the object is to an unmanaged version of the object, so be careful. Altering its fields will not alter the managed version. At this point its best to discard your unmanaged version and deal only with the managed object.

I can see why you're confused. I hope that helps.

Upvotes: 1

Related Questions