I have an Android app that uses SQLite with its json1 extension as its database backend. While this works the SQL required to manipulate the JSON is very hard to understand and even harder to maintain. Consequently, I am currently experimenting with Realm as an alternative. While Realm is for the most part intuitive LinkingObjects is a feature that I do not fully understand. Consider the following classes that I currently use
public class GridNode extends RealmObject
{
@PrimaryKey
private int id = 0;
@Index
private int lx = 0;
@Index
private int ly = 0;
@LinkingObjects("gridnode")
private final RealmResults<PassPoint> passpoints = null;
//getters, setters & constructors
}
public class PassPoint extends RealmObject
{
private GridNode gridnode;//each passpoint refers to one distinct GridNode object
private int hits;
private int lastVisited;
//getters, setters & constructors
}
In the current SQLite version of my data I identify the GridNode
used by each PassPoint
by referencing its AUTO_INCREMENTing id
field. With Realm things get much simpler since I can simply use the GridNode itself as an attribute of the PassPoint.
This is where things get a bit less clear. Suppose I retrieve an existing GridNode
from a Realm
by running a RealmQuery e.g.
myrealm.where(GridNode.class).equalTo("lx",23).equalTo("ly",32).findFirst();
Reading between the lines I have concluded that running this query will not only fetch the GridNode I am after but run an implicit query using my
@LinkingObjects("gridnode")
private final RealmResults<PassPoint> passpoints = null;
annotation to retrieve a list of all PassPoint
objects that refer to the GridNode in question.
Very handy but I find myself wondering if this does not come at a price - the time required to run that query. And suppose I have a few other classes that also refer to GridNodes in which case I will have further @LinkingObjets
annotation which would then result in further implicit queries?
As opposed to that if I were to simply record a GridNode id I could then deal with identifying the relevant GridNode myself as and when required? In effect, trading convenience for speed and responsiveness?
Or perhaps I have quite simply read wrongly between the lines and this is not at all how @LinkingObjects
works?
Another thing that is not quite clear - as you will note gridnode
is a private member of the PassPoint
class. How then am I able to create the @LinkingObjects("gridnode")
annotation in my GridNode
class without the compiler complaining about me trying to access a member that is not visible from outside the PassPoint
class?
Reading between the lines I have concluded that running this query will not only fetch the GridNode I am after but run an implicit query
No. Not quite.
As the Realm documentation states here:
All fetches (including queries) are lazy in Realm, and the data is never copied.
This means that the simple case of defining a query does just that - it defines it. But it does not evaluate/execute the query until the user specifically requests it. An object with a query field (e.g. a LinkingObjects
field) therefore provides a simple method by which the user may execute a query, but does not execute it autonomously just because the object itself is loaded. It is only run when a findFirst
or findAll
(or similar) call is made.
So if you never actually access the GridNode.passpoints
field, it is never executed.
You could prove this to yourself with a simple experiment:-
GridNode
from the Realm with no linked PassPoint
.Passpoint
to the realm with a reference to the same GridNode
.Passpoint
.As to your second question, the simple answer is that the protection level of your model fields applies only to the Java models of your data; it is not applied to the underlying Realm models.