Android Room:如何在不使用 "autoGenerate = true" 的情况下自动生成主 ID(避免 SQLite 关键字 AUTOINCREMENT)?

Android Room: How to auto generate primary id, without using "autoGenerate = true" (To avoid SQLite keyword AUTOINCREMENT)?

背景

最近,我了解到不鼓励在 SQLite 中使用 AUTOINCREMENT

https://www.sqlite.org/autoinc.html

关键字AUTOINCREMENT实际上是令人困惑的。 as,真正的意思是自动生成id的算法方法。

即使我们不使用关键字 AUTOINCREMENT,并且在插入时不提供 id,id 仍然会自动生成。

例如,

DROP TABLE cities;

CREATE TABLE cities (
   id INTEGER NOT NULL PRIMARY KEY,
   name TEXT NOT NULL
);

INSERT INTO cities (name)
VALUES( 'San Jose');

INSERT INTO cities (name)
VALUES( 'New York');

即使没有AUTOINCREMENT关键字

也会生成下面的table
id  name
========
1   San Jose
2   New York

我想在 Android 房间

中实现相同的行为

而不是使用以下(将应用 SQLite AUTOINCREMENT

@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
private long id;

我在我的实体中使用class

@PrimaryKey
@ColumnInfo(name = "id")
private long id;

但是,我注意到我需要显式地为id分配一个非零正值,只有插入才会成功。

如果id的值为0或-1,则插入不会成功

我希望我们不需要手动分配 id,即使不使用 Room autoGenerate = true

但是,这似乎没有按预期工作。我可以知道为什么会这样吗?

您不需要在 Android 房间中达到同样的效果。在 SQLite 中,类型为 INTEGER PRIMARY KEY 的列是 ROWID 的别名,除非您指定 WITHOUT ROWID.

因此,除非另有说明,否则您的 id 将收到一个未使用的整数。

不推荐 AUTOINCREMENT 关键字的原因是,除非它是 PRIMARY KEY,否则不太可能需要接受 CPU、内存使用、磁盘方面的成本space 和 I/O 开销。但是,使用 PRIMARY KEY 实际上是个好主意。请注意,您共享的页面从未声称您不应该使用 PRIMARY KEY,它只是不鼓励使用 AUTOINCREMENT 关键字。

I expect we need not to assign id manually, even without using Room autoGenerate = true.

不需要使用autogenerate = true,并且具有相同的生成值。你可以使用(另一种方式稍后展示):-

@PrimaryKey
@ColumnInfo(name = "id")
private Long id; /* or private Long = null; */

注意使用 Long 对象而不是 long 原语。然后将 id 设置为 null 以生成要生成的值或具有合适的构造函数。

Room 看到空值,在 PRIMARY KEY 和 a non-primitive 整数类型的情况下,并从生成的 SQL 中省略该列。 =18=]

作为基于您的架构的示例,请考虑:-

@Entity
class Cities {
   @PrimaryKey
   private Long id;
   private String name;

   @Ignore
   public Cities(String name) {
      this.name = name;
   }
   @Ignore
   public Cities(Long id, String name) {
      this.id = id;
      this.name = name;
   }
   public Cities(){}

   public Long getId() {
      return id;
   }

   public void setId(Long id) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }
}

使用方便的@Insert 例如:-

@Dao
interface CitiesDao {
    @Insert
    long insert(Cities city);
}

或者,您可以使用 @Query 来使用适合的 INSERT SQL。例如以下将插入一行,仅给出名称和生成的 ID。 :-

@Query("INSERT INTO cities (name) VALUES(:name)")
long insert(String name);
  • 重要的因素是包括没有 id 列的特定列。

使用上述(2 种方法)的示例:-

    citiesdao.insert(new Cities("San Jose"));
    citiesdao.insert(new Cities("New York"));
    citiesdao.insert(new Cities(100L,"San Francisco"));
    citiesdao.insert(new Cities("Nevada"));
    citiesdao.insert("Dallas");
  • 您可能不想使用带有特定 ID 的第三个插入(或者可以使用 onConflict = IGNORE)。

以上结果(通过 App Inspection):-