首页 > 解决方案 > Android房间数据库插入/更新序列

问题描述

我有一个带有 Room 数据库的应用程序,包括 DAO 和存储库。事件顺序如下:

  1. 插入新行。
  2. 将行发送到服务器
  3. 更新该行以指示该行已被发送。

问题是新行的 ID 在我发送到服务器之前或更新时并不总是可用的。因此,DAO 更新方法不起作用,因为它没有正确的 ID。
在我继续之前让插入返回 ID 是否有技巧?我知道这是在规避异步进程的好处,但在这种情况下可能是必要的。我希望其他人可能已经解决了这个问题。

标签: databaseinsertandroid-room

解决方案


问题是在我发送到服务器之前,新行的 ID 并不总是可用

对于 Room 中的表,如果通过便利 @Insert 插入行,则始终有一个唯一标识可用插入行的值(如果使用则不同@Query("INSERT INTO .....")

  • 请注意,如果由于捕获/处理冲突而未插入该行,则返回的值将为 -1。

在我继续之前让插入返回 ID 是否有技巧?

不是真正的技巧,至少如果ID是整数类型,更多的是预期/预期的用法。只需让insert Dao 返回 Long(如果 java 则返回 long)

例如(Java)

@Insert
long insert(TheEntity theEntity);

或(科特林)

@Insert
fun insert(theEntity: TheEntity): Long

返回的 Long/long 将是rowid列的值或其别名。

rowid是所有表都有的列(除了那些用 WITHOUT ROWID 定义的表,Room 不允许),尽管它是一个隐藏列。如果您编写使用 @PrimaryKey 注释的整数类型,则该列将是rowid的别名。

  • 注意整数类型,你可以有

    • 长长的,
    • 整数,整数整数,
    • 短,短,
    • 字节,字节,
    • 甚至,尽管它很无用,布尔值,布尔值。
  • 然而,Long,long 是最适合id列的值,因为 SQLite 可以存储一个 64 位有符号整数,它等于 Long/long。因此,为什么插入只能返回 Long/long。

    • 不使用 Long/long SQLite 的优势很小(如果有的话)会将值存储在从 1 字节到 8 字节的尽可能小的空间中。因此,值 1 无论是 byte/short/int/long 在存储在数据库中时都会占用一个字节。

    • 例如对于 Kotlin 代码fun insert(toDoData: ToDoData): Int,你会得到error: Not sure how to handle insert method's return type. public abstract int insert(@org.jetbrains.annotations.NotNull()

非整数 ID 类型/复合主键

其他列类型 String、Byte[]、Double、Float 等,或复合主键,不会是 rowid 列的别名。要从这些其他类型中获取主键,您可以使用返回的 rowid,因为它对行是唯一的,然后获取主键,例如 (for @PrimaryKey val id: String)

@Query("SELECT id FROM todo_table WHERE rowid=:rowid" )
fun getPrimaryKeyByRowid(rowid: Long): String`

当然,您可以绕过获取 PrimayKey 值并传递,然后使用rowid值来确定要更新的行,但不使用@Update便捷方法/函数,而是@Query使用UPDATE .... WHERE rowid=:passRowid.


推荐阅读