Realm backlink like a foreign key - android

I am trying to find a way to insert a child object in its parent object without having to do a query for each one.
Let me be more specific:
class Parent extends RealmObject {
String id;
RealmList<Child> childs;
}
class Child extends RealmObject {
String parentId;
}
And suppose I make a request in a webservice to get child object of different parents... so, now I have:
List<Child> childsOfDifferentParents;
And I want to add to link each child to its correct parent.
The only way I've found so far was, query for each parent and add it.
But, since it is too many objects, it wouldn't be efficient. What should I do?

Related

Save linked objects Primary key value already exists Relationships

I have just started to use RealmDB and cannot figure out how to save linked object correctly, to implement a sort of foreign key
Here is my main User model.
public class UserModel extends RealmObject {
#PrimaryKey
public Long id;
public String firstName;
public String lastName;
public UserSettings userSettingsModel;
}
UserSettings Model is defined as follows.
public class UserSettingsModel extends RealmObject {
#PrimaryKey
private Long id;
public String email;
public RealmList<Car> cars;
}
And Car is a model itself.
public class Car extends RealmObject {
#PrimaryKey
private Long id;
public String model;
}
The problem is that when I am trying to save UserModel it tries to recreate all objects assigned to it. So before I saving user model I have already creates some Car objects.
I don't need to create them, but to reference like the foreign key in SQL databases. And when I am retrieving a user from the database it should automatically load all related data by primary keys.
Is it possible to achieve such behavior using Realm ?
Thanks for help. Solved this problem by using the copyToRealmOrUpdate method instead of copyToRealm.
You should create a managed object using realm.createObject(clazz, pkValue); if it doesn't exist yet, then set it as value or add it to the RealmList that you get another managed object.
You can also create managed objects from unmanaged objects with copyToRealmOrUpdate() (if the object has a primary key).
And when I am retrieving a user from the database it should automatically load all related data by primary keys.
The RealmList allows access to the related objects, and in fact, is also queryable by calling .where() on it. However, this is not based on primary keys. That feature is tracked under "computed fields".

Find all child realm objects where the parent's id is X

In this example, the docs talked about getting the parent objects while specifying queries for the child objects.
Is there a way for getting the child objects while specifying a query for the parent object?
In the given example, can I search for dogs who are of brown color with the user named John?
EDIT: Since Realm 3.5.0, you can actually use the "backlinks" mentioned in the comment section. Rejoice!
In fact, since Realm 3.0.0, bidirectional links are a performance bottleneck, so using backlinks is the preferred way.
The way it works is:
public class User extends RealmObject {
private RealmList<Dog> dogs;
}
public class Dog extends RealmObject {
#LinkingObjects("dogs")
private final RealmResults<User> owners = null;
}
Now you can do:
realm.where(Dog.class).equalTo("color", "Brown").equalTo("owners.name", "John").findAll();
OLD ANSWER:
You can only search for dogs with a given user if you have an object link to the User.
public class Dog extends RealmObject {
//...
private User user;
}
Then you could do
realm.where(Dog.class).equalTo("color", "Brown").equalTo("user.name", "John").findAll();

How to describe tree model in Realm?

So I'm curious is it possible to put a model like this:
class Parent{
Parent kid;
}
class Parent{
Kid kid
}
class Kid{
//valuable stuff
}
Parent -> Parent -> ... -> Parent -> Kid. The problem that it can be as much levels as possible of Parent classes and only in the end after 3 or 7 passes Kid class. Now I'm just going recursively over JSONObject and storing one big JSONObject but I would love to put model into Realm and not going over it every time. Any suggestion on how to treat such a structure is really welcome.
I would model it as a recursive datastructure, e.g.:
class Person {
private Person person;
private Parent parent;
private Kid kid;
}
and then use appropriate null-checks to determine what kind of Person it is.

ForeignCollection create or update

How do I create OR update a ForeignCollection in OrmLite?
If I try to simply add an object to a ForeignCollection, the add method acts as a create (insert into) method, but if the object already exists I will get an error about not having a unique primary key. I don't want duplicates to appear with autoincrementing primary keys, so this is fine to get this notice.
If I use the update method, then it will error if there is nothing to update.
It seems that the foreigncollection object doesn't have a way to tell me if an object is already existing in the database.
So is the only way to write a separate query myself, see if each object exists and drop the ones that have changed?
If you are using for example :
#DatabaseTable(tableName = "question")
public class QuestionDb implements Serializable {
#ForeignCollectionField(foreignFieldName = "question", eager = true)
private ForeignCollection<AnswerDb> answers;
}
#DatabaseTable(tableName="answers")
public class AnswerDb implements Serializable{
#DatabaseField (foreign=true,canBeNull=true,columnName=FIELD_QUESTIONID)
private QuestionDb question;
}
You will have to use the function createOrUpdate of the AnswersDB.
answerYouWantToAdd.setQuestion(yourQuestion);
answerDao.createOrUpdate(answerYouWantToAdd);

how to link my getEmptyForeignCollection() object with my parent object?

I want to persist an object with two foreignCollections.
But when I try to query the object, my foreignId is always null.
I already read this answers but it doesn't really help me: Collections in ORMLite
VOPerception perception = new VOPerception();
perception.setOrientation(daoOrientation.createIfNotExists(
orientationLocalizer.getCurrentOrientation()));
ForeignCollection<VOAccessPoint> fAp =
daoPerception.getEmptyForeignCollection("accessPoints");
fAp.addAll(wifiLocalizer.getCurrentScanResultMap());
perception.setAccessPoints(fAp);
daoPerception.create(perception);
List<VOPerception> list = daoPerception.queryForAll();
here data are correctly stored but VOAccessPoint objects have no link with the parent VOPerception object.
Here are my two classes:
public class VOPerception {
#DatabaseField(generatedId=true)
private int per_id;
#ForeignCollectionField(eager=true)
ForeignCollection<VOAccessPoint> accessPoints;
...
}
public class VOAccessPoint{
#DatabaseField(generatedId=true)
private int ap_id;
#DatabaseField(foreign=true,columnName="apForeignPerception_id")
private VOPerception apForeignPerception;
...
}
Your queryForAll() is returning no objects because none of your VOAccessPoint instances ever set their apForeignPerception field to be perception. Adding the VOAccessPoint objects using the ForeignCollection added them to the DAO but did not automagically assign their apForeignPerception field.
You should do something like:
...
Collection<VOAccessPoint> points = wifiLocalizer.getCurrentScanResultMap();
for (VOAccessPoint point : points) {
point.setApForeignPerception(perception);
}
fAp.addAll(points);
...
I can see how you might think that this would be handled automagically but at the time they are added to the ForeignCollection, the perception is not even assigned. I suspect that there is a missing feature for ORMLite here or at least a better exception.
I would recommend to use assignEmptyForeignCollection(Obj parent, fieldName). This will create a new foreign collection and all objects you will add via add(Obj element) will have the parent value set automatically.

Categories

Resources