CRUD операции в Realm + RXJava

235
11 января 2018, 22:00

Дело в том что я до этого удалял и обновлял записи в Realm таким образом:

public <T extends RealmObject> void deleteDataById(String publicId, Class<T> clazz){
    Realm realm = Realm.getDefaultInstance();
    realm.executeTransactionAsync(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            RealmResults<T> result = realm.where(clazz).equalTo("publicId", publicId).findAll();
            result.deleteAllFromRealm();
        }
    });
}
public <T extends RealmObject> void updateData(T object) {
    try (Realm realmInstance = Realm.getDefaultInstance()) {
        realmInstance.executeTransaction(realm -> {
            Log.d(LOG_TAG, "updateData");
            realm.insertOrUpdate(object);
        });
    }
}

Но так как я изучаю RXJava, решил переделать CRUD операции под RX.

Вот как я делаю запись в базу:

public <T extends RealmObject> Flowable<RealmResults<T>> getAllData(Class<T> clazz) {
    Realm realm = Realm.getDefaultInstance();
    RealmQuery<T> query = realm.where(clazz);
    if(realm.isAutoRefresh()) {
        Log.d(LOG_TAG, "getData isAutoRefresh()");
        return query.findAllAsync().asFlowable().filter(RealmResults::isLoaded);
    } else {
        Log.d(LOG_TAG, "getData, !isAutoRefresh()");
        return Flowable.just(query.findAll());
    }
}

С одной стороны подумываю так и оставить Update и Delete операции, так как они ничего не возвращают, но и с другой, мне кажется они хотя бы должны возвращать результат операции. Может я не правильно представляю.

Попробовал с Flowable.defer(), Flowable.just(), но все равно ошибка в flatMap():

flatMap (io.reactivex.functions.Function>) in Flowable cannot be applied to (anonymous io.reactivex.functions.Function)

Вот как я пытался сделать:

public Flowable deleteDataById(String publicId) {
    Realm realm = Realm.getDefaultInstance();
    return realm.asFlowable()
            .flatMap(new Function<Realm, Boolean>() {
                @Override
                public Boolean apply(Realm realm) throws Exception {
                    return realm.where(ServiceModel.class)
                            .equalTo("publicId", publicId)
                            .findAll()
                            .deleteAllFromRealm();
                }
            })  
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread());
}

Вопрос:

  1. Правильны ли мои представления касательно Update и Delete.

  2. Как правильно переделать Update и Delete под RX?

Answer 1

Не совсем понимаю, зачем реализовывать прям CRUD, я делал вот так, пример на котлине, но думаю суть будет понятна.

Чтобы можно было использовать вместе с Observable и Flowable

fun <T : RealmModel> queryFromRealm(func: (Realm) -> T?): Observable<T> {
    return queryFromRealmFlowable(func).toObservable()
}
fun <T : RealmModel> queryFromRealmFlowable(func: (Realm) -> T?): Flowable<T> {
    return Flowable.defer<T> {
        val realm = Realm.getDefaultInstance()
        try {
            realm.beginTransaction()
            val result = func(realm)
            var resultCloned: T? = null
            if (RealmObject.isValid(result)) {
                resultCloned = realm.copyFromRealm(result)
            }
            realm.commitTransaction()
            if (resultCloned == null) {
                return@defer Flowable.empty()
            } else
                return@defer Flowable.just<T>(resultCloned)
        } catch (e: Exception) {
            realm.cancelTransaction()
            Flowable.error<T>(e)
        } finally {
            realm.close()
        }
    }
}

И для списков объектов

fun <T : RealmModel> queryListFromRealm(func: (Realm) -> List<T>): Single<List<T>> {
    return Single.defer<List<T>> {
        val realm = Realm.getDefaultInstance()
        try {
            realm.beginTransaction()
            val result = func(realm)
            val resultCloned = result.map { realm.copyFromRealm(it) }
            realm.commitTransaction()
            return@defer Single.just<List<T>>(resultCloned)
        } catch (e: Exception) {
            realm.cancelTransaction()
            Single.error<List<T>>(e)
        } finally {
            realm.close()
        }
    }
}

Дальше я это использую уже в репозиториях, т.е. так называемые crud операции все идут там.

fun fetchPhotoList(): Single<List<Photo>> {
    return RealmProvider.queryListFromRealm { realm -> realm.where(Photo::class.java).findAllSorted("date") }
}

так же можно использовать и в цепочке операторов

fun loadHouseList(limit: Int, offset: Int, query: String): Single<List<House>> {
    return api.loadHouseList(limit, offset, query)
            .flatMap { list -> RealmProvider.queryListFromRealm {realm -> realm.copyToRealmOrUpdate(list) } }
}

Плюс моего подхода в том, что я отвязываю объекты от Realm, т.е. они перестают быть active record. С этим решается проблема, что такие объекты можно передавать между потоками, а значит инстанс realm можно использовать только в том потоке, в котором он был создан.

На всякий случай покажу весь класс c extention func, вдруг будет полезно кому-то

READ ALSO
Размещение виджета ниже ListView

Размещение виджета ниже ListView

Как разместить TextView ниже ListView ?

213
Как найти цифру 0 в в заданном числе JAVA

Как найти цифру 0 в в заданном числе JAVA

Нужно найти в заданном с клавиатуры шестизначном числе, цифры 0

208
Нужно полностью обновить SQLite базу данных при повышении версии кода приложения

Нужно полностью обновить SQLite базу данных при повышении версии кода приложения

Имеется приложение, которое работает с локальной базой данных SQLiteВ этой БД хранятся ссылки на файлы и ключевые слова, по которым можно найти...

199
Как по нажатию на кнопку добавлять экземпляр моего класса в List без повторений

Как по нажатию на кнопку добавлять экземпляр моего класса в List без повторений

чтобы по нажатию добавлялся только один экземпляр в ArrayList например

144