会议室-插入新值后执行删除 [英] Room - Delete executes after I insert new values

查看:61
本文介绍了会议室-插入新值后执行删除的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究Rxjava2,并且试图将Room Library与Rxjava2集成.问题是:我有一个填充的表,每次登录该应用程序时,都需要删除该表,然后在数据库中插入新的内容.另外,删除和插入工作正常,但是当我尝试删除表内容后尝试插入新值时,delete方法将删除所有新值.(代码的某些部分在kotlin中,而其他部分在java中)
我已经尝试过: RxJava2 + Room :在clearAllTables()调用之后没有将数据插入数据库中,但是没有成功.

DAO

@Dao
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(list:List<Something>)

@Query("DELETE FROM SomethingTable")
fun delete()

@Query("SELECT * FROM SomethingTable")
fun getAll(): Flowable<List<Something>>

我的类调用了DAO(CallDao)

//insert
fun insertInDB(list: List<Something>) {
    Completable.fromAction {
        dbDAO!!.insert(list)
    }.observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.io())
            .subscribe()
}

//delete
fun clean() {
    Completable.fromAction {
        dbDAO!!.delete()
    }.observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.single())
            .subscribe()
}

//search all
fun findAll(): Observable<List<Something>>? {
    return Observable.create { subscriber ->
        dbDAO!!.getAll()
                .subscribeOn(Schedulers.io())
                .subscribe {it->
                    subscriber.onNext(it)
                }
    }
}

当我单击登录按钮时调用的方法

private void clearAndInsertInDB() {
CallDao callDao= new CallDao(getActivity());
//delete all table values
callDao.clean();

Something sm = new Something("test1", "test2");
ArrayList<Something> list = new ArrayList<>();
list.add(sm);
list.add(sm);
//insert new values
callDao.insertInDB(list);

//get all new values in DB
callDao.findAll()
      .observeOn(AndroidSchedulers.mainThread())
      .subscribe(res -> {
      //here gives me a IndexOutOfBoundsException
      Log.d("logDebug", res.get(0).getCodeExemple());
    });
}

也欢迎在我的代码中进行任何更正:),但是主要问题是delete方法删除所有新的插入值,并且应该只删除旧的值.

解决方案

您正在进行两个异步调用:一个删除用户,另一个重新插入用户.但是,即使先调用callDao.clean();方法,然后再调用callDao.insertInDB(list);,也不能保证clean()操作将在insertInDB()操作之前完成(因为这是异步调用的工作方式).

正在发生的事情:

相反,您应该链接异步调用,这样,第二个调用就会在您知道第一个已经完成时立即被调用.

如何使用RxJavaCompletable实现该目标?按照在此答案中所述使用andThen运算符

您应该修改clean()insertInDB()方法以返回Completables,使用andThen链接它们,然后订阅.

使用RxJava和andThen()的简单示例

FakeDatabase db = Room.databaseBuilder(this, FakeDatabase.class, "fake.db")
                      .fallbackToDestructiveMigration()
                      .build();

UserDao userDao = db.userDao();

User user1 = new User("Diego", "Garcia Lozano", "diegogarcialozano@fake.com");
User user2 = new User("Juan", "Perez", "juanperez@fake.com");
User user3 = new User("Pedro", "Lopez", "pedrolopez@fake.com");
List<User> users = new ArrayList<>();
users.add(user1);
users.add(user2);
users.add(user3);

Completable deleteAllCompletable = Completable.fromAction(userDao::deleteAll);
Completable insertUserCompletable = Completable.fromAction(() -> userDao.insertAll(users));

deleteAllCompletable
            .andThen(Completable.fromAction(() -> System.out.println("Delete finished")))
            .andThen(insertUserCompletable)
            .andThen(Completable.fromAction(() -> System.out.println("Insert finished")))
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.single())
            .subscribe();

在执行后检查Logcat,您可以看到操作以正确的顺序执行:

2018-11-19 16:07:02.056 10029-10047/? I/System.out: Delete finished
2018-11-19 16:07:02.060 10029-10047/? I/System.out: Insert finished

然后,我使用工具. org/"rel =" noreferrer> SQLite浏览器,发现插入操作正常.

在DAO中使用@Transaction

您可以完全不用RxJava来获得更好的解决方案.相反,您可以使用 @Transaction 批注,如本文中所述,.看起来像这样:

Dao

@Dao
public abstract class UserDao {

    @Transaction
    public void deleteAndCreate(List<User> users) {
        deleteAll();
        insertAll(users);
    }

    @Query("DELETE FROM User")
    public abstract void deleteAll();

    @Insert
    public abstract void insertAll(List<User> users);
}

活动

Completable.fromAction(() -> userDao.deleteAndCreate(users))
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.single())
            .subscribe();

检查表格

的表

我个人会使用@Transaction注释.

I'm studying Rxjava2 and I'm trying to integrate the Room Library with Rxjava2. The problem is: I have a populated table and every time I login in the app, I need to delete this table and then insert a new content in database. Separately, the delete and insert works fine, but when I try to insert new values after I delete the table content, the delete method deletes all the new values.. (some parts of the code is in kotlin and others in java)
I already tried this:
RxJava2 + Room: data is not being inserted in DB after clearAllTables() call, but no success..

DAO

@Dao
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(list:List<Something>)

@Query("DELETE FROM SomethingTable")
fun delete()

@Query("SELECT * FROM SomethingTable")
fun getAll(): Flowable<List<Something>>

My class that calls the DAO (CallDao)

//insert
fun insertInDB(list: List<Something>) {
    Completable.fromAction {
        dbDAO!!.insert(list)
    }.observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.io())
            .subscribe()
}

//delete
fun clean() {
    Completable.fromAction {
        dbDAO!!.delete()
    }.observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.single())
            .subscribe()
}

//search all
fun findAll(): Observable<List<Something>>? {
    return Observable.create { subscriber ->
        dbDAO!!.getAll()
                .subscribeOn(Schedulers.io())
                .subscribe {it->
                    subscriber.onNext(it)
                }
    }
}

Method that is called when I click in login button

private void clearAndInsertInDB() {
CallDao callDao= new CallDao(getActivity());
//delete all table values
callDao.clean();

Something sm = new Something("test1", "test2");
ArrayList<Something> list = new ArrayList<>();
list.add(sm);
list.add(sm);
//insert new values
callDao.insertInDB(list);

//get all new values in DB
callDao.findAll()
      .observeOn(AndroidSchedulers.mainThread())
      .subscribe(res -> {
      //here gives me a IndexOutOfBoundsException
      Log.d("logDebug", res.get(0).getCodeExemple());
    });
}

Any corrections in my code is also welcome :) , but the main problem is that the delete method deletes all the new insert values and it should delete only the old values.

解决方案

You are making two asynchronous calls: one to delete the users and another to insert them again. However, even though you call first the callDao.clean(); method and after that you call callDao.insertInDB(list); , it is not guaranteed that the clean() operation will finish before the insertInDB() operation (because that's how asynchronous calls work).

This is what is happening:

Instead, you should chain your async calls , in such a way that the second one gets called as soon as you know that the first one has already finished.

How to achieve that using RxJava and Completable? Using the andThen operator as stated in this answer

You should modify your clean() and insertInDB() methods to return the Completables, use andThen to chain them, and then subscribe.

Simple example using RxJava and andThen()

FakeDatabase db = Room.databaseBuilder(this, FakeDatabase.class, "fake.db")
                      .fallbackToDestructiveMigration()
                      .build();

UserDao userDao = db.userDao();

User user1 = new User("Diego", "Garcia Lozano", "diegogarcialozano@fake.com");
User user2 = new User("Juan", "Perez", "juanperez@fake.com");
User user3 = new User("Pedro", "Lopez", "pedrolopez@fake.com");
List<User> users = new ArrayList<>();
users.add(user1);
users.add(user2);
users.add(user3);

Completable deleteAllCompletable = Completable.fromAction(userDao::deleteAll);
Completable insertUserCompletable = Completable.fromAction(() -> userDao.insertAll(users));

deleteAllCompletable
            .andThen(Completable.fromAction(() -> System.out.println("Delete finished")))
            .andThen(insertUserCompletable)
            .andThen(Completable.fromAction(() -> System.out.println("Insert finished")))
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.single())
            .subscribe();

Checking the Logcat after execution, you can see that the operations were executed in the proper order:

2018-11-19 16:07:02.056 10029-10047/? I/System.out: Delete finished
2018-11-19 16:07:02.060 10029-10047/? I/System.out: Insert finished

Afterwards, I checked the content of the database using the tool SQLite Browser and saw that the insert worked properly.

Using @Transaction in the DAO

You can get a better solution for your problem without using RxJava at all. Instead, you can define a Transaction in your DAO using the @Transaction annotation, as explained in this post. It would look something like this:

Dao

@Dao
public abstract class UserDao {

    @Transaction
    public void deleteAndCreate(List<User> users) {
        deleteAll();
        insertAll(users);
    }

    @Query("DELETE FROM User")
    public abstract void deleteAll();

    @Insert
    public abstract void insertAll(List<User> users);
}

Activity

Completable.fromAction(() -> userDao.deleteAndCreate(users))
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.single())
            .subscribe();

Checking the table

Personally, I would do it with the @Transaction annotation.

这篇关于会议室-插入新值后执行删除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆