会议室-插入新值后执行删除 [英] Room - Delete executes after I insert new values
问题描述
我正在研究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()
操作之前完成(因为这是异步调用的工作方式).>
正在发生的事情:
相反,您应该链接异步调用,这样,第二个调用就会在您知道第一个已经完成时立即被调用.
如何使用RxJava
和Completable
实现该目标?按照在此答案中所述使用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
然后,我使用工具
在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屋!