有什么方法可以使Room在没有AUTOINCREMENT的情况下生成自动生成的主键?

时间:2018-09-27 21:30:53

标签: android sqlite android-sqlite android-room

“我的会议室”数据库具有以下实体:

@Entity
public class SmsMessage {
    @PrimaryKey
    public long id;

    public boolean incoming;
    public String sender;
    public String receiver;
    public String body;
    public long timestamp;
}

尝试在数据库中插入多个项目时,失败,并显示以下RuntimeException

SQLiteConstraintException: PRIMARY KEY must be unique (code 19)

生成的SQL CREATE TABLE语句如下:

CREATE TABLE `SmsMessage` (
    `id`    INTEGER NOT NULL,
    `incoming`  INTEGER NOT NULL,
    `sender`    TEXT,
    `receiver`  TEXT,
    `body`  TEXT,
    `timestamp` INTEGER NOT NULL,
    PRIMARY KEY(`id`)
);

这似乎与INTEGER NOT NULL PRIMARY KEY不同,尽管我在the SQLite documentation中找不到有关此行为的任何文档。

似乎我必须使用@PrimaryKey (autogenerate=true)才能使Room自动生成主键值。使用autogenerate=true查看生成的数据库时,将生成以下SQL:

CREATE TABLE `SmsMessage` (
    `id`    INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    `incoming`  INTEGER NOT NULL,
    `sender`    TEXT,
    `receiver`  TEXT,
    `body`  TEXT,
    `timestamp` INTEGER NOT NULL
);

似乎autogenerate=true对应于SQLite AUTOINCREMENT。但是,the SQLite documentation清楚地表明,不需要AUTOINCREMENT(并且在大多数情况下不建议)来自动生成唯一的主键。 AUTOINCREMENT的目的基本上是为了防止重复使用已使用但已删除的主键。

  

AUTOINCREMENT关键字强加了额外的CPU,内存,磁盘空间和磁盘I / O开销,如果没有严格要求,应避免 。通常不需要。

     

在SQLite中,类型为INTEGER PRIMARY KEY的列是ROWID的别名(WITHOUT ROWID表中除外),该别名始终是64位带符号整数。

     

在INSERT上,如果未明确为ROWID或INTEGER PRIMARY KEY列提供值,则将自动用未使用的整数填充该整数,通常比当前使用的最大ROWID多一个整数。无论是否使用AUTOINCREMENT关键字,都是如此。

     

如果在INTEGER PRIMARY KEY之后出现AUTOINCREMENT关键字,则会更改自动ROWID分配算法,以防止在数据库的生命周期内重复使用ROWID。换句话说, AUTOINCREMENT的目的是防止重复使用先前删除的行中的ROWID

因此,似乎通常不需要或不建议使用@PrimaryKey(autogenerate=true)。但是仅单独使用@PrimaryKey根本不会自动生成值。

我如何告诉Room我想要的是'id' INTEGER NOT NULL PRIMARY KEY

1 个答案:

答案 0 :(得分:4)

目前无法实现-唯一的选择是AUTOINCREMENT。您可以将existing feature request标记为该用例的最新进展。