With the new Room Database in Android, I have a requirement where there are two sequential operations that needs to be made:
removeRows(ids);
insertRows(ids);
If I run this, I see (on examining the db) that there are some rows missing - I assume they are being deleted after inserting. viz. the first operation is running in parallel to the second.
If I use a transaction block, such as this, then it's all fine - the first operation seems to complete before doing the second:
roomDb.beginTransaction();
removeRows(ids);
roomDb.endTransaction();
insertRows(ids);
It's also fine if I give a sleep in-between instead:
removeRows(ids);
Thread.sleep(500);
insertRows(ids);
There doesn't seem to be much documentation for Room, and was wondering if I should use the transaction block like the above when I have sequential operations to be done, or is there any better way of doing it.
EDIT : After @CommonsWare pointed out, @Query
are asynchronous, while @Insert
and @Delete
are synchronous. In view of this, how would I get a query which deletes rows to be async:
@Query("DELETE from table WHERE id IN(:ids)")
int removeRows(List<Long> ids);
According to the build output I get Deletion methods must either return void or return int (the number of deleted rows)
, if I try to wrap the return type in a Flowable
.
As pointed out on documentation for Transaction , you can do following:
@Dao
public abstract class ProductDao {
@Insert
public abstract void insert(Product product);
@Delete
public abstract void delete(Product product);
@Transaction
public void insertAndDeleteInTransaction(Product newProduct, Product oldProduct) {
// Anything inside this method runs in a single transaction.
insert(newProduct);
delete(oldProduct);
}
}
As @CommonsWare pointed out, @Query are asynchronous , while @Insert , @Delete , @Update are synchronous.
If you want to execute multiple queries in single transaction , Room also provides a method for that as mentioned below.
roomDB.runInTransaction(new Runnable() {
@Override
public void run() {
removeRows(ids);
insertRows(ids);
}
});
I hope this will solve your problem.
For Room transactions in Kotlin you can use:
@Dao
interface Dao {
@Insert
fun insert(item: Item)
@Delete
fun delete(item: Item)
@Transaction
fun replace(oldItem: Item, newItem: Item){
delete(oldItem)
insert(newItem)
}
}
@Dao
abstract class Dao {
@Insert
abstract fun insert(item: Item)
@Delete
abstract fun delete(item: Item)
@Transaction
open fun replace(oldItem: Item, newItem: Item){
delete(oldItem)
insert(newItem)
}
}
You'll get error: Method annotated with @Transaction must not be private, final, or abstract.
without open modifier.
I believe when we are using DAO interfaces, still we can perform transaction using default interface methods. We need to add the annotation @JvmDefault and @Transaction and we can perform any operation inside that, which belong to single transaction.
@Dao
interface TestDao {
@Insert
fun insert(dataObj: DataType)
@Update
fun update(dataObj: DataType): Completable
@Delete
fun delete(dataObj: DataType): Completable
@Query("DELETE FROM $TABLE_NAME")
fun deleteAllData()
@Query("SELECT * FROM $TABLE_NAME ORDER BY id DESC")
fun getAllData(): Single<List<DataType>>
@JvmDefault
@Transaction
fun singleTransaction(dataList: List<DataType>) {
deleteAllData()
dataList.forEach {
insert(it)
}
}
}
here's the solution to this problem:
@Query("SELECT * FROM friend WHERE id = :id")
Friend getFriendByID(int id);
@Delete
void delete(Friend friend);
Friend friendToBeDeleted = friendDAO.getFriendByID(id);
friendDAO.delete(friendToBeDeleted);
You have to go through two steps!
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.