Androidの新しいルームデータベースでは、2つの連続した操作を行う必要があるという要件があります。
_removeRows(ids);
insertRows(ids);
_
これを実行すると、いくつかの行が欠落していることが(dbを調べると)表示されます-挿入後に削除されていると思います。つまり最初の操作は2番目の操作と並行して実行されます。
このようなトランザクションブロックを使用する場合は、問題ありません。最初の操作は2番目の操作を行う前に完了したようです。
_roomDb.beginTransaction();
removeRows(ids);
roomDb.endTransaction();
insertRows(ids);
_
代わりに中間に睡眠を与えても大丈夫です:
_removeRows(ids);
Thread.sleep(500);
insertRows(ids);
_
ルームのドキュメントはあまりないようで、シーケンシャル操作を実行するときに上記のようなトランザクションブロックを使用する必要があるのか、それとももっと良い方法があるのか疑問に思っていました。
[〜#〜] edit [〜#〜]:@CommonsWareが指摘した後、_@Query
_は非同期ですが、_@Insert
_と_@Delete
_は同期です。これを考慮して、非同期にする行を削除するクエリをどのように取得しますか:
_@Query("DELETE from table WHERE id IN(:ids)")
int removeRows(List<Long> ids);
_
ビルド出力によると、Flowable
で戻り値の型をラップしようとすると、Deletion methods must either return void or return int (the number of deleted rows)
が返されます。
トランザクション のドキュメントで指摘されているように、次のことができます。
@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);
}
}
@CommonsWareが指摘したように、@ Queryは非同期ですが、@Insert、@Delete、@Updateは同期です。
単一のトランザクションで複数のクエリを実行する場合、Roomは以下で説明する方法も提供します。
roomDB.runInTransaction(new Runnable() {
@Override
public void run() {
removeRows(ids);
insertRows(ids);
}
});
これで問題が解決することを願っています。
この問題の解決策は次のとおりです。
@Query("SELECT * FROM friend WHERE id = :id")
Friend getFriendByID(int id);
@Delete
void delete(Friend friend);
Friend friendToBeDeleted = friendDAO.getFriendByID(id);
friendDAO.delete(friendToBeDeleted);
あなたは2つのステップを経なければなりません!
DAOインターフェイスを使用している場合でも、デフォルトのインターフェイスメソッドを使用してトランザクションを実行できると考えています。アノテーション@JvmDefaultおよび@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)
}
}
}