java – Android Realm copyToRealmOrUpdate creates duplicates of nested objects-ThrowExceptions

Exception or error:

I have following classes:

public class Note extends RealmObject {

    @PrimaryKey
    private String id;

    private Template template;

    // other primitive fields, getters & setters
}

public class Template extends RealmObject {

    private String name;

    private String color;

    // other primitive fields, getters & setters
}

I get my data from backend via Retrofit & Gson, so I have ready-to-use java objects in response.

Let’s imagine that backend returns me same three Notes each time I call it.
When I get the list of Note objects, I do the following:

private void fetchNotesAndSave() {
    List<Notes> notes = getNotesViaRetrofit();        

    Realm realm = Realm.getInstance(mContext);
    realm.beginTransaction();
    realm.copyToRealmOrUpdate(notes);
    realm.commitTransaction();
    realm.close();
}

After that I call these lines to check count of stored objects:

int notesCount = mRealm.where(Note.class).findAll().size();
int templatesCount = mRealm.where(Template.class).findAll().size();

For the first time:

notesCount == 3;
templatesCount == 3;

That’s right. But, if I call the server again, get same notes (same primaryKey ids), and call fetchNotesAndSave() again, I’ll get these results:

notesCount == 3;
templatesCount == 6;

Each time I call copyToRealmOrUpdate(), nested objects, that are inside of objects with primaryKey are duplicated – not updated.

Is there any way to change this behaviour?
Please let me know if you need more information. Thanks in advance!

How to solve:

It is because your Template class doesn’t have any primary key. In that case these objects are inserted again as there is no guarantee that the referenced template objects safely can be updated, even if they are part of another object that has a primary key.

If you add a @PrimaryKey to your template class it should work as you expect it to.

###

If you can’t provide a PK as suggested, you might want to use the following work around to avoid duplicates.

for (Note note: notes) {
    realm.where(Note.class)
    .equalTo("id", note.getId())
    .findFirst()
    .getTemplate()
    .deleteFromRealm();
}
realm.copyToRealmOrUpdate(notes);

Leave a Reply

Your email address will not be published. Required fields are marked *