有没有办法让 Room 生成一个不自动递增的自动生成主键?

Is there any way to make Room generate an autogenerating primary key without AUTOINCREMENT?

我的房间数据库有以下实体:

@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对应SQLiteAUTOINCREMENT。然而,the SQLite documentation 非常清楚地表明不需要 AUTOINCREMENT(并且在大多数情况下不推荐)以自动生成唯一的主键。 AUTOINCREMENT 的目的基本上是为了防止重复使用已使用但已删除的主键。

The AUTOINCREMENT keyword imposes extra CPU, memory, disk space, and disk I/O overhead and should be avoided if not strictly needed. It is usually not needed.

In SQLite, a column with type INTEGER PRIMARY KEY is an alias for the ROWID (except in WITHOUT ROWID tables) which is always a 64-bit signed integer.

On an INSERT, if the ROWID or INTEGER PRIMARY KEY column is not explicitly given a value, then it will be filled automatically with an unused integer, usually one more than the largest ROWID currently in use. This is true regardless of whether or not the AUTOINCREMENT keyword is used.

If the AUTOINCREMENT keyword appears after INTEGER PRIMARY KEY, that changes the automatic ROWID assignment algorithm to prevent the reuse of ROWIDs over the lifetime of the database. In other words, the purpose of AUTOINCREMENT is to prevent the reuse of ROWIDs from previously deleted rows.

所以似乎通常不需要也不推荐使用 @PrimaryKey(autogenerate=true)。但是单独使用@PrimaryKey根本不会自动生成值。

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

目前不可能 - 唯一的选择是 AUTOINCREMENT。您可以为 existing feature request 加注星标以获取有关此用例支持的进度更新。