1. ホーム
  2. android

[解決済み] Android Room Persistence Library。アップサート

2022-08-25 09:44:19

質問

Android の Room 永続化ライブラリには、オブジェクトまたはコレクションに対して機能する @Insert および @Update アノテーションが含まれています。しかし、私は、データがデータベースに存在するかどうかわからないため、UPSERT を必要とするユースケース (モデルを含むプッシュ通知) を持っています。

Sqliteはネイティブにupsertを持っておらず、回避策はこちらで説明されています。 SO質問 . そこにある解決策を考えると、Roomにどのように適用するのでしょうか?

より具体的には、どのようにしたら、外部キー制約を破らない Room の挿入または更新を実装できますか? onConflict=REPLACE で挿入を使用すると、その行への外部キーの onDelete が呼び出されます。私の場合、onDelete はカスケードを引き起こし、行を再挿入すると、その外部キーを持つ他のテーブルの行が削除されます。これは意図された動作ではありません。

どのように解決するのですか?

こんな感じでBaseDaoを作ればいいのかもしれません。

アップサートを@Transactionで保護する。 挿入に失敗したときだけ更新するようにする。

@Dao
public abstract class BaseDao<T> {
    /**
    * Insert an object in the database.
    *
     * @param obj the object to be inserted.
     * @return The SQLite row id
     */
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    public abstract long insert(T obj);

    /**
     * Insert an array of objects in the database.
     *
     * @param obj the objects to be inserted.
     * @return The SQLite row ids   
     */
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    public abstract List<Long> insert(List<T> obj);

    /**
     * Update an object from the database.
     *
     * @param obj the object to be updated
     */
    @Update
    public abstract void update(T obj);

    /**
     * Update an array of objects from the database.
     *
     * @param obj the object to be updated
     */
    @Update
    public abstract void update(List<T> obj);

    /**
     * Delete an object from the database
     *
     * @param obj the object to be deleted
     */
    @Delete
    public abstract void delete(T obj);

    @Transaction
    public void upsert(T obj) {
        long id = insert(obj);
        if (id == -1) {
            update(obj);
        }
    }

    @Transaction
    public void upsert(List<T> objList) {
        List<Long> insertResult = insert(objList);
        List<T> updateList = new ArrayList<>();

        for (int i = 0; i < insertResult.size(); i++) {
            if (insertResult.get(i) == -1) {
                updateList.add(objList.get(i));
            }
        }

        if (!updateList.isEmpty()) {
            update(updateList);
        }
    }
}