问题
Suppose there is a Dao
class with the following two methods:
1)
delete(items: List<Item>): Completable
2)
insert(items: List< Item >): Single<List<Long>>
How can I chain them into a @transaction
method in Dao
class starting with ‘delete method’ and then returning ‘insert method’ result?
I want to have a method with a signature like this:
@Transaction
fun deleteAndInsert(): Single<List<Long> > {
...
}
回答1:
I'm assuming your main goal is to have the return type of deleteAndInsert()
as Single
.
You can achieve that with small modifications
- first by making
delete()
andinsert()
functions synchronous. - Since
@Transaction
only works synchronously, we need to create another function that calls bothdelete()
andinsert()
. Also, annotate this function with@Transaction
- Create another new function that creates a
Single
and calls the above function.
abstract class SampleDao{
protected abstract fun delete()
protected abstract fun insert(items: List<Item>) : List<Long>
@Transaction
protected open fun deleteAndInsertSync(items: List<Item>): List<Long>{
delete()
return insert(items)
}
fun deleteAndInsert(items:List<Item>): Single<List<Long>>{
return Single.create {
it.onSuccess(deleteAndInsertSync(items))
}
}
}
回答2:
I don't think it is possible.
I once tried it and I got a compile-time error saying:
"Method annotated with @Transaction must not return deferred/async return type io.reactivex.Single. Since transactions are thread confined and Room cannot guarantee that all queries in the method implementation are performed on the same thread, only synchronous @Transaction implemented methods are allowed. If a transaction is started and a change of thread is done and waited upon then a database deadlock can occur if the additional thread attempts to perform a query. This restriction prevents such situation from occurring."
回答3:
If you delete
and insert
methods are marked with annotation, they are executing in a transaction. So, basicly you don't need to mark your deleteAndInsert
method with this annotation. So, than:
fun deleteAndInsert(items: List< Item >): Single<List<Long>> {
return delete().andThan(insert(items))
}
回答4:
- Method annotated with @Transaction must not return deferred/async return type io.reactivex.Single. Since transactions are thread confined and Room cannot guarantee that all queries in the method implementation are performed on the same thread, only synchronous @Transaction implemented methods are allowed. If a transaction is started and a change of thread is done and waited upon then a database deadlock can occur if the additional thread attempts to perform a query. This restrictions prevents such situation from occurring.
When I decompile code to java, I see.
public interface CustomerDao { @Transaction @NotNull List deleteAndCreate(@NotNull List var1); @Query("DELETE FROM customer") @NotNull Completable deleteAll(); @Insert @NotNull List insertAll(@NotNull List var1); @Metadata( mv = {1, 1, 15}, bv = {1, 0, 3}, k = 3 ) public static final class DefaultImpls { @Transaction @NotNull public static List deleteAndCreate(CustomerDao $this, @NotNull List users) { Intrinsics.checkParameterIsNotNull(users, "users"); $this.deleteAll(); return $this.insertAll(users); } } }
回答5:
Get Ids of new Data
then delete all items where not in the new data
@Query("DELETE FROM product WHERE id NOT IN(:idsNewItems)")
@Override
public abstract void deleteOldItems(List<String> idsNewItems)
;
来源:https://stackoverflow.com/questions/55463342/how-to-return-a-rx-single-transaction-using-room-db