Ситуация в следующем: приложение делает REST запрос на получение данных, сохраняет их в базе, каким-то образом модифицирует, затем снова их получает с сервера. Все довольно тривиально, казалось бы, если бы не одно «но» — где мои локальные изменения?К сожалению, Realm не поддерживает обновление данных с пропуском конкретных полей, как это было сделано в реквесте на гитхабе проекта, например
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")
https://github.com/realm/realm-java/issues/2179
что было бы довольно удобно. Давайте рассмотрим на примерах. Представим, что у нас есть чат, в котором у сообщений есть флаг «прочитано». Наш REST интерфейс не возвращает об этом состоянии никаких данных и вся информация о том, было ли сообщение прочитано или нет, хранится только локально.В общем, после выполнения следующей строчки в коде
realm.copyToRealmOrUpdate(list);
Флаг будет сброшен на дефолтное значение.Вариантов несколько, некоторые из них не совсем верные, но работают, а некоторые прям вообще идеально подходят. Давайте рассмотрим два из них.
Хранение локальных изменений отдельно.
Честно говоря, сначала я придерживался именно этого подхода. Допустим, для объекта Message я создавал класс MessageData, в котором хранил флаг прочтения, дату прочтения и прочие параметры, которые не должны были перезаписываться при обновлении данных с сервера. Primary key у объектов будут одинаковые, и для отображения локальных данных надо сделать дополнительный запрос в базу. Смотрится это немного кривовато, но я лично не обнаружил на тот момент иных способов решения проблемы.
Сохранение Json (внезапно)
Отложив на какое-то время проблему в долгий ящик с предыдущим решением, я переключился на решение иных проблем (читай — одолела текучка). Когда же у меня получилось разгрести очередные завалы, я вернулся к рассматриваемой здесь проблеме — да как же так, думал я, неужели в Realm не рассмотрели никаких альтернатив.Чем дольше я думал об этом, тем сильнее склонялся к тому, что это в общем-то логично. Посудите сами — мы можем обновлять объект с сохранением данных только в том случае, если мы его перед этим из базы получили. Иначе (согласно логике и названию метода copyToRealmOrUpdate) обновляем подходящие объекты полностью (читай — все полученные данные будем считать отныне актуальными). От верного решения меня отвлекало еще то, что используя Retrofit и какие-то промежуточные операции, я оперировал не json строкой, а массивом элементом (с которыми попутно еще что-то делал).Ладно, не буду ходить вокруг да около. Смотрите сами.
RealmHelper.get().beginTransaction();
RealmHelper.get().delete(SampleAccount.class);
RealmHelper.get().commitTransaction();
String name = "name";
SampleAccount account = new SampleAccount(name);
account.isRead = true;
account.save();
Diagnostics.i("1. " + account.toString());
String json = "[{\"name\":\"name\",\"ts\":0}]";
List<SampleAccount> list = new ArrayList<>();
list.add(new SampleAccount(name));
RealmHelper.get().beginTransaction();
RealmHelper.get().createOrUpdateAllFromJson(SampleAccount.class, json);
RealmHelper.get().commitTransaction();
account = RealmHelper.get().where(SampleAccount.class).equalTo("name", name).findFirst();
Diagnostics.i("2. " + account.toString());
И что мы видим в логах?
om.isidroid.platform I/Diagnostics: 1. SampleAccount{isRead=true, ts=1501066478906}
com.isidroid.platform I/Diagnostics: 2. SampleAccount{isRead=true, ts=0}
Магия!
@sashatinkoff Поздравляю! Вы получили личную награду!
Вы можете нажать на бейдж, чтобы увидеть свою страницу на Доске Почета.
@sashatinkoff, поздравляю! Вы добились некоторого прогресса на Голосе и были награждены следующими новыми бейджами:
Вы можете нажать на любой бейдж, чтобы увидеть свою страницу на Доске Почета.
Чтобы увидеть больше информации о Доске Почета, нажмите здесь
Если вы больше не хотите получать уведомления, ответьте на этот комментарий словом
стоп