带有延迟外键的 Android Room

Ant*_*nit 8 android foreign-keys deferred android-room

我有几个定期从服务器更新的表 ( Benefit, Branch, Coupon) 和另外两个仅本地的表 ( FavoriteBenefit, UsedCoupon)。ER图如下所示: ER图

每当Benefit在服务器上删除a 时,我还想从FavoriteBenefit. 为此,我可以使用onDelete = ForeignKey.CASCADE,每当Benefit数据库中不再存在父级时,它FavoriteBenefit也会被删除。听起来不错。

每当我@Insert(onConflict = OnConflictStrategy.REPLACE)用来更新数据库中的好处时就会出现问题 。REPLACE实际上是一个执行DELETEINSERT,但DELETE在内部触发onDeleteFavoriteBenefit,因此,在该表中的所有数据被删除。

CouponUsedCoupon表也会出现类似的问题。)


我正在寻找一种方法来暂时禁用外键约束,直到事务结束。也就是说,不要在事务期间验证外键,而只在事务结束时验证。我仍然希望 Room 自动删除没有有效父级的实体。


似乎通过在定义上设置将外键标记为延迟应该完全符合我想要实现的目标。deferred = true@ForeignKey

布尔延迟 ()

外键约束可以推迟到事务完成。如果您在单个事务中对数据库进行批量插入,这将非常有用。默认情况下,外键约束是即时的,但您可以通过将此字段设置为 true 来更改它。

但即使我设置了deferred标志,它似乎也没有效果,因为FavoriteBenefit每次仍然被删除。

我是否deferred错误地理解了标志?

c0n*_*nst 6

我不知道它是否仍然与您相关,但我遇到了类似的问题。我试图deferred在两个地方都放置标志:关系类本身和作为编译指示。在这两种情况下,项目都因OnConflictStrategy.REPLACE策略而被删除(执行DELETE您提到的操作)。我发现的解决方法是使用“ UPSERT-like”查询。UPSERT语句支持是去年在 SQLite 中添加的,所以 Room 还不支持它,但你可以这样写:

@Dao
abstract class BaseDao<T> {

    /**
     * Insert an item in the database.
     *
     * @param item the item to be inserted.
     * @return The SQLite row id
     */
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    abstract fun insert(item: T): Long

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

    /**
     * Update an item from the database.
     *
     * @param item the item to be updated
     */
    @Update
    abstract fun update(item: T)

    /**
     * Update an array of items from the database.
     *
     * @param item the item to be updated
     */
    @Update
    abstract fun update(item: List<T>)

    @Transaction
    fun upsert(item: T) {
        val id = insert(item)
        if (id == -1L) {
            update(item)
        }
    }

    @Transaction
    fun upsert(items: List<T>) {
        val insertResult = insert(items)
        val updateList = mutableListOf<T>()

        for (i in insertResult.indices) {
            if (insertResult[i] == -1L) {
                updateList.add(items[i])
            }
        }

        if (updateList.isNotEmpty()) {
            update(updateList)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

代码背后的逻辑很简单——如果表已经包含记录(这是通过过滤rowids在插入后检查的)——我们应该更新它们。

学分