我有一个待办事项列表应用程序,使用空间来存储数据。
我的数据类如下所示
@Entity
data class ToDoItem(
@PrimaryKey val id: Int,
val title: String,
val description: String
)
当我在列表中添加新项目时,我是这样做的
viewModel.addItem(ToDoItem(0,title.toString(), description.toString()))
所以它运行得很好。我的问题是,为什么我总是可以将0
作为主键值发送?为什么我不必获取最后一项主键值并将其作为参数发送?它是怎么运作的?为什么我总是可以发送硬编码的0
,而且它工作起来没有任何问题?
3条答案
按热度按时间wfauudbj1#
我的问题是,为什么我总是可以发送0作为主键值?
@Insert
函数,则onConflict=
值。为什么我不必获取最后一项主键值并将其作为参数发送?
Int
和@primayKey
注解)的组合是允许生成值的SQLite特例。同样,这取决于您插入行的方式。它是怎么运作的?为什么我总是可以发送硬编码的0,而且它工作起来没有任何问题?
说明
对于SQLite,它是一个数据库,Room是它的 Package 器。
INTEGER
和PRIMARY 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提供的例子相反。有人建议,
Long
**。原因是:INTEGER
支持64位有符号整数,因此从理论上讲,Int不够大。事实上,SQLite将根据需要在尽可能小的空间中存储该值(低至1个字节)。@Insert
带注解的函数插入时返回的id是一个长整型或长整型数组,因此不需要使用Int
的toInt
方法。(有关id的检索示例,请参阅demo链接)。Long?=null
,因此默认情况下会生成id。autoGenerate=true
。AUTOINCREMENT
(也称为autoGenerate=true
),则会产生SQLITE_FULL错误。您可能希望参考
AUTOINCREMENT
ON CONFLICT
ClauseInt=0
iq0todco2#
查看this answer有关Room如何处理副本的信息。从您的代码中可以看出,您要么创建了ID为
0
的重复条目,要么每次都在更新相同的条目。当您尝试检索所有条目时会发生什么情况?具体地说,您是否使用
id=0
获得了多个条目?如果不是,是否看起来只有一个条目带有id=0
?或者它会自动为您生成ID?iq3niunx3#
您需要使用AutoGenerate属性
您的主键注解应如下所示:
@PrimaryKey(AutoGenerate=True)
欲了解更多详情,请登录:https://developer.android.com/reference/androidx/room/PrimaryKey#autoGenerate()