通过Room在SQLite中添加项时需要放入项的ID是什么?安卓系统

rdlzhqv9  于 2022-11-15  发布在  SQLite
关注(0)|答案(3)|浏览(150)

我有一个待办事项列表应用程序,使用空间来存储数据。
我的数据类如下所示

@Entity
data class ToDoItem(
    @PrimaryKey val id: Int,
    val title: String,
    val description: String
)

当我在列表中添加新项目时,我是这样做的

viewModel.addItem(ToDoItem(0,title.toString(), description.toString()))

所以它运行得很好。我的问题是,为什么我总是可以将0作为主键值发送?为什么我不必获取最后一项主键值并将其作为参数发送?它是怎么运作的?为什么我总是可以发送硬编码的0,而且它工作起来没有任何问题?

wfauudbj

wfauudbj1#

我的问题是,为什么我总是可以发送0作为主键值?

  • 具体原因取决于您插入行的方式。如果使用带注解的@Insert函数,则onConflict=值。

为什么我不必获取最后一项主键值并将其作为参数发送?

  • 因为如下所述,整数类型(如Int@primayKey注解)的组合是允许生成值的SQLite特例。同样,这取决于您插入行的方式。

它是怎么运作的?为什么我总是可以发送硬编码的0,而且它工作起来没有任何问题?

  • 如下所述
    说明

对于SQLite,它是一个数据库,Room是它的 Package 器。INTEGERPRIMARY KEY列类型的组合是一种特殊情况,其中该列是名为rowid的特殊列的别名。所有的表都有rowid(除了一些特殊的情况,比如WITHOUT ROWID表,Room不支持)。
如果没有为rowid指定值,则SQLite确定要分配的值(通常比该表的最后一个rowid大1)。AUTOINCREMENT关键字的使用有一种变化,只有在指定了INTEGER PRIMARY KEY时才能使用该关键字。这实现了一个规则,即rowid必须大于分配的任何rowid(即使该行已被删除)。
AUTOINCREMENT效率低下,因为它需要一个表(SQLITE_SEQUENCE),对于插入到具有AUOINCREMENT编码的表中的任何行,必须搜索和更新该表。
在Room中指定autoGenerate = true会导致使用AUTOINCREMENT。
Room在编译时查看@Entity注解中定义的实体列表中的@Entity注解类,并使用类中的成员/字段来确定表的定义。
如果成员/字段使用@PrimaryKey进行注解,并且成员/变量的类型是整型类型,如Long,Int,则它将是rowid的别名。
因此,Room必须决定在插入行时何时以及何时不应用某个值。
如果值为空(LONG?INT?)然后Room知道不应用一个值,所以不会。
但是,与您的示例一样,如果您有Int=0而不是Int?=null,则如果autogenerate为真,则Room不赋值,并生成值。如果没有autoGenerate=true,则Room分配0(在Int=0的情况下),如果该值没有设置为其他值,则每个id都将为0。正如PRIMARY KEY所暗示的UNIQUE,那么只有1行可以具有值为0的rowid,并且UNIQUE冲突发生。
SQLite用于处理某些冲突,从而在一定程度上控制如何处理冲突。也就是说,INSERT后面可以跟关键字OR和一个操作,该操作可以是:

  • ABORT(默认)
  • ROLLBACK(如果不在指定的事务中,则将中止)
  • FAIL
  • IGNORE(忽略冲突)
  • REAPLCE(覆盖现有行后忽略冲突)

Room允许您在使用@Insert注解时使用onConflict参数指定其中一个。
因此,由于没有autogenerate=true,因此重复插入带有0的id将如何依赖onConflict参数。
如果它是IGNORE(onConflict=OnConflictStrategy.IGNORE),则只插入第一行。
如果是REPLACE(onConflict=OnConflictStrategy.REPLACE),则每次后续插入都会覆盖前一行。

建议

尽管它与Room提供的例子相反。有人建议,

  • a)整数主键使用的类型为**Long**。原因是:
  • SQLite的INTEGER支持64位有符号整数,因此从理论上讲,Int不够大。事实上,SQLite将根据需要在尽可能小的空间中存储该值(低至1个字节)。
  • 使用@Insert带注解的函数插入时返回的id是一个长整型或长整型数组,因此不需要使用InttoInt方法。(有关id的检索示例,请参阅demo链接)
  • b)使用Long?=null,因此默认情况下会生成id。
  • c)除非严格需要,否则不使用autoGenerate=true
  • 通常在插入9223372036854775807之前,id会更大
  • 如果指定了AUTOINCREMENT(也称为autoGenerate=true),则会产生SQLITE_FULL错误。
  • 否则将尝试返回未使用的值,而不是错误。
  • 9223372036854775807的行数超出了任何现有存储设备的存储容量。

您可能希望参考

iq0todco

iq0todco2#

查看this answer有关Room如何处理副本的信息。从您的代码中可以看出,您要么创建了ID为0的重复条目,要么每次都在更新相同的条目。
当您尝试检索所有条目时会发生什么情况?具体地说,您是否使用id=0获得了多个条目?如果不是,是否看起来只有一个条目带有id=0?或者它会自动为您生成ID?

iq3niunx

iq3niunx3#

您需要使用AutoGenerate属性
您的主键注解应如下所示:
@PrimaryKey(AutoGenerate=True)
欲了解更多详情,请登录:https://developer.android.com/reference/androidx/room/PrimaryKey#autoGenerate()

相关问题