realm-java: Ignored fields list for copyToRealmOrUpdate

User case from SO: http://stackoverflow.com/questions/35244823/realm-for-android-how-to-sync-server-data-to-realm-database

If one field is stored locally, it would be convenient to ignore the local field while updating the existing RealmObject.

API proposal:

public <E extends RealmObject> E copyToRealmOrUpdate(E object, String... ignoredFields)

About this issue

  • Original URL
  • State: open
  • Created 8 years ago
  • Reactions: 22
  • Comments: 37 (16 by maintainers)

Most upvoted comments

I also have similar issues with copyToRealmOrUpdate and relations. The idea is this: I fetch data from server which contains relationship information as a primary key:

{
"id": 1,
"relatedObject": 101
}

public class Item extends RealmObject {
    @PrimaryKey private int id;
    private RelatedObject relatedObject;
}

And I already have related objects stored locally. So when I call copyToRealmOrUpdate I get empty related objects (i.e. only PK is stored, all other fields become nulls).

As a workaround I use “raw” POJOs to decode for Retrofit and then manually process them, establishing relations and creating/updating RealmObjects from those POJOs. It’s very annoying and introduces a lot of boilerplate code.

So, how about an option to turn off deep copying, i.e. copyToRealmOrUpdate(object, deep=false)?

I mean, we’re on mobile, so sending full relationship objects with each data update via network is very unhealthy.

Note: it’s different from just ignoring some fields, because I can obviously receive relationship update (i.e. different PK) which must be reflected locally.

I don’t think createOrUpdateAllFromJson is an acceptable solution, I feel this completely breaks any implementation of retrofit + converters (for example) in your network layer, as is my case. I can’t use retrofit 2.0 and moshi to deserialize json objects into model classes i can work with, if I am forced to use createOrUpdateAllFromJson. Otherwise we have to hard code so many things.

We are not going to implement an ignore list of fields. Our JSON methods already support partial updates, so you can use those if you want. Also, there are a number of other features on our roadmap that would be better suited for this without inflating our API surface and complicate our existing copyToRealm methods considerably.

  1. Inheritance ( #761 ) -> FullClass extends PartialClass
  2. Support for @SerializableName or similar ( #2476 ) to allow our JSON methods to be used more easily.

I completely understand why you would want to Use Retrofit/GSON, but there is something fundamentally wrong if you first want to deserialize a “partial” object into the “full” Java definition and then expect other layers of your application to understand that the object isn’t what it claims to be.

We do realize the experience can be frustrating right now as you are basically forced to implement the partial update yourself and we do hope to improve on the situation, but it will not be as an “ignore” list.

@cmelchior @beeender while watching this video I was kinda wondering - while you can’t really use an ignore fields exclusion list because Proguard can eat your model class (unless you use the original field name during annotation processing, I guess) ~ I was wondering about an easier option

realm.insertOrUpdate(item); // persists nulls by default
realm.insertOrUpdate(item, true); // true being the default, "persist nulls"
realm.insertOrUpdate(item, false); // ignores null values

That way it’s actually +1 method for realm.insertOrUpdate and I’m guessing +1 for each proxy, which is okay, and not that complex?

Is this a bad idea? It’s 2 AM, I might be full of terrible ideas.

Thanks for the reminder @guillermomuntaner . I will merge the two issues so we only have the discussion in one place.

Copy paste from #2179


Feature request:

Partial updates

How?

Related to issue #1853 I agree that only updating not-null values is not a correct approach, since null can be sometimes a desired value and also because of not nullable primitive types with default values.

But, what about a call to specify a list of the fields that one want to overwrite (or preserve)? copyToRealmOrUpdateOverwritingFields("field1","field2") copyToRealmOrUpdatePreservingFields("field1","field2") copyToRealmOrUpdate(obj).preserve("field1","field2")

In case the object does not exist in realm, the “fields to be preserved” can be initialized with default values, which i think is quite solid from a design pov.

Thoughts on this?

My issue scenario:

Im doing a cache with Realm where objects from one class can be updated online or locally based on user interaction. This is a problem, because every single online update using copyToRealmOrUpdate() will overwrite all the local updates which i would like to keep. The option to use json would work for me, but since im dealing with complex json and doing custom deserialization plus other manipulations in order to get the POJO i am storing, having to serialize to Json just to update feels a bit excessive.

As reference found also other related issue with a scenario like mine #1540

This is related to the issue #2179 I opened. I see 2 use-cases (both of them I am currently facing and solving via inconvenient helper methods):

  1. To be able to create specific local fields that are never updated via copyToRealmOrUpdate. In this case, the proposed @LocalField can work.
  2. To be able to partially update a model explicitly specifying fields. E.g. i have “compact” models coming from some endpoints and “extended” models coming from others (think of extended user model with tons of information vs a tiny user model with username and avatar to include in other objects like posts and replies). Problem i faced is that saving “compact” models using copyToRealmOrUpdate() will destroy all the information already saved in “extended” models. In this case @LocalField approach is not enough. Via annotations, i can thing of something like @DontOverwriteIfNull but as we discussed in other issues, null sometimes can be a desired value. I like the proposed public <E extends RealmObject> E copyToRealmOrUpdate(E object, String... ignoredFields)

5 Years afterwards and it’s not implemented, any chance to get such feature?

@ismdcf findFirst()/createObject() and then set the expected fields

while you can’t really use an ignore fields exclusion list because Proguard can eat your model class (unless you use the original field name during annotation processing, I guess)

Yes, proguard is a problem, we have it for the class name as well. The proxy will generate a map of Class to the realm name by annotation processor, and we access the map on runtime through https://github.com/realm/realm-java/blob/master/realm/realm-library/src/main/java/io/realm/internal/RealmProxyMediator.java#L78

Or maybe the API could be more generic to have even more flexibility:

interface RealmInsertionFilter<T extends RealmModel> {
    boolean shouldInsert(T objectToBeInserted, String fieldName);
}

RealmInsertionFilter insertionFilter = new RealmInsertionFilter() {
    boolean shouldInsert(Foo foo, String fieldName) {
        if (fieldName.equals("noPersist")) {
            return false;
        }
        return true;
    }
}

realm.insertOrUpdate(item, insertionFilter);