Android的Room持久性库优雅地包含了适用于对象或集合的@Insert和@Update注释.然而,我有一个用例(包含模型的推送通知),需要UPSERT,因为数据库中可能存在数据,也可能不存在数据.

Sqlite本身没有upsert,在这SO question中描述了解决方法.给出那里的解决方案,如何将它们应用到Room?

更具体地说,我如何在Room中实现不会违反任何外键约束的INSERT或UPDATE?使用INSERT WITH onConflict=Replace将导致调用该行的任何外键的onDelete.在我的示例中,onDelete导致级联,重新插入一行将导致删除其他表中具有外键的行.这不是预期的行为.

推荐答案

也许你可以把你的BaseDao做成这样.

使用@Transaction保护upsert操作,

@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);
        }
    }
}

Android相关问答推荐

我遇到了一个HashMaps对象没有存储在Firebase数据库中的问题.HashMap的一个对象put方法未被存储

原因平滑滚动的滞后懒惰列在android jetpack compose

Yarn 机器人导致活动未找到,但Gradlew Run工作正常

Android Jetpack Compose调用view-model函数仅一次

如何在初始合成期间在可组合函数中调用/获取远程API中的数据[防止无限重组]

Play Google上发布的一款应用的房间数据库迁移

如何在jetpack compose中使可组合的屏幕zoom 到不同的手机(屏幕)尺寸?

为一组闪烁的可组合项制作动画,控制同步/定时

在 Android Studio 中获取更新版本的 Picasso 库的错误警告消息

Jetpack Compose 中带有权重的行和 AnimatedVisibility 会 destruct UI

从 Jetpack Compose 中的 IconButton 中删除黑色色调

Android:ActivityCompat.requestPermissions 不显示弹窗(Android 13,targetSdkVersion=33)

如何关闭可组合对话框?

获取模板向导配方类 Intellij 中的应用程序包名称

如何在 Jetpack Compose 中为中心对齐设置动画?

房间创建三四表关系

android 13 版本是否会影响 android 12 目标应用程序

使用 Room 在 SQLite 中保存复杂的 JSON 响应

为什么在try 实例化 Mediaplayer 时会出现 NullPointerException?安卓Kotlin

未解决的参考:getIntentSender / try 在 Jetpack Compose 中获取电话号码时