如何将 Android 房间列从 notNull=true 更新为 notNull=false?

How do I updated an Android Room column from notNull=true to notNull=false?

问题: 对于 Android Room,它使用预填充的数据库,我似乎无法将 table 列从 notNull=truenotNull=false?预填充的数据库模式是正确的,但我无法获得 Android 房间以正确更新以匹配:

我做了什么: 我编辑了 json 架构文件,删除了特定列的 NOT NULL,并在 fields 我更新了相同字段的列信息为"notNull": false。我尝试了一个迁移,不知道它是否正确,使用 ALTER TABLE Notes ADD COLUMN 'QuestionID' INTEGER 并且它实际上再次将 json 文件更新为 NOT NULL。我似乎找不到有关如何执行此操作的信息? Entity 没有这些注释,我不确定是否有必要在 Entity 中定义这些注释,因为此数据库有其他 table 没有这些注释,并且它们正在通过编译没有问题。我确定这是另一个 80/20 规则,我很愚蠢并且遗漏了一些东西。

json 文件中的示例 Table Question、Quote、Term 和 Deleted 字段需要 notNull=false 并不断改回到 true... 并且预填充的 table 是正确的。

        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`NoteID` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `SourceID` INTEGER NOT NULL, `CommentID` INTEGER NOT NULL, `QuestionID` INTEGER NOT NULL, `QuoteID` INTEGER NOT NULL, `TermID` INTEGER NOT NULL, `TopicID` INTEGER NOT NULL, `Deleted` INTEGER NOT NULL, FOREIGN KEY(`SourceID`) REFERENCES `Source`(`SourceID`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`CommentID`) REFERENCES `Comment`(`CommentID`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`TopicID`) REFERENCES `Topic`(`TopicID`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
        "fields": [
          {
            "fieldPath": "noteID",
            "columnName": "NoteID",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "sourceID",
            "columnName": "SourceID",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "commentID",
            "columnName": "CommentID",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "questionID",
            "columnName": "QuestionID",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "quoteID",
            "columnName": "QuoteID",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "termID",
            "columnName": "TermID",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "topicID",
            "columnName": "TopicID",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "deleted",
            "columnName": "Deleted",
            "affinity": "INTEGER",
            "notNull": true
          }```

json 文件中的架构是基于实体生成的,更改它不会有任何区别。它甚至不是必需的(除非使用 AutoMigration)。

The pre-populated database schema is correct but I cannot get Android Room to update correctly to match:

您必须相应地更改实体或相应地转换预填充的数据库。再次注意实体定义了 Room 的期望。

使用的语言对确切答案很重要。

如果使用 Kotlin,注释可能是:-

data class Note(
    @PrimaryKey(autoGenerate = true)
    val NoteId: Long,
    val SourceID: Long?,
    val CommentID: Long?,
    val QuestionID: Long?,
    val QuoteID: Long?,
    val TermID: Long, //<<<<< NOT NULL 
    val TopicID: Long?,
    val Deleted: Long?
)

生成的 java 然后显示 table 创建为 :-

_db.execSQL("CREATE TABLE IF NOT EXISTS `Note` (`NoteId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `SourceID` INTEGER, `CommentID` INTEGER, `QuestionID` INTEGER, `QuoteID` INTEGER, `TermID` INTEGER NOT NULL, `TopicID` INTEGER, `Deleted` INTEGER, FOREIGN KEY(`SourceID`) REFERENCES `Source`(`SourceID`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`CommentID`) REFERENCES `Comment`(`CommentID`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`TopicID`) REFERENCES `Topic`(`TopicID`) ON UPDATE NO ACTION ON DELETE NO ACTION )");

即那些长?没有 NOT NULL(TermID 列没有 NULL,因为使用了 Long 而不是 Long?)。

对于 Java,列类型不能是允许 NULL 的原始类型,因为它们必须有一个值并且不能为 null,因此 Room 将派生 NOT NULL。只有对象类型(例如 Long 而不是 long)将被视为允许 NULL。要强制 NOT NULL,则需要使用 @NotNull 注释。

所以 Java 等效项(命名为 Java 注意允许两者都是 used/compiled)可以是:-

@Entity(
        foreignKeys = {
                @ForeignKey(entity = Source.class,parentColumns = {"SourceID"},childColumns = {"SourceID"}),
                @ForeignKey(entity = Comment.class,parentColumns = {"CommentID"},childColumns = {"CommentID"}),
                @ForeignKey(entity = Topic.class,parentColumns = {"TopicID"}, childColumns = {"TopicID"})
        }
)
class JavaNote {
    @PrimaryKey(autoGenerate = true)
    long NoteID=0; // primitives cannot be NULL thus imply NOT NULL
    Long SourceID;
    Long CommentID;
    Long QuestionID;
    Long QuoteID;
    @NotNull
    Long TermID; // or long TermID
    Long TopicID;
    Long Deleted;
}

生成的 java 然后将 table 创建为 :-

_db.execSQL("CREATE TABLE IF NOT EXISTS `JavaNote` (`NoteID` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `SourceID` INTEGER, `CommentID` INTEGER, `QuestionID` INTEGER, `QuoteID` INTEGER, `TermID` INTEGER NOT NULL, `TopicID` INTEGER, `Deleted` INTEGER, FOREIGN KEY(`SourceID`) REFERENCES `Source`(`SourceID`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`CommentID`) REFERENCES `Comment`(`CommentID`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`TopicID`) REFERENCES `Topic`(`TopicID`) ON UPDATE NO ACTION ON DELETE NO ACTION )");
  • TermID 再次被故意编码为使用 NOT NULL

编译后生成的java可用。 在生成的java(使用Android视图)中发现member/class名称与class注解相同的@Database后缀为_Impl。语句本身在 createAlltables 方法中。

例如:-