我有以下实体SessionLabel

@Entity(
    foreignKeys =
    @ForeignKey(
            entity = Label.class,
            parentColumns = {"id", "archived"},
            childColumns = {"labelId", "archived"},
            onUpdate = CASCADE,
            onDelete = SET_DEFAULT))
    public class Session {

    @PrimaryKey(autoGenerate = true)
    public long id;

    @Nullable
    public String label = null;

    public boolean archived = false;
}

@Entity(primaryKeys = {"id", "archived"})
public class Label {

    @NonNull
    public String id;

    public boolean archived = false;
}


删除附加到LabelSession时,我得到的是NOT NULL constraint failedSession.archived

我在这里做错了什么?

最佳答案

我认为问题在于使用public boolean archived = false;中的布尔类型。

由于boolean是Java主要类型,因此它具有隐式@NonNull(使用NOT NULL约束创建表)

对于Room,您不能(我相信)设置SQLite表中生成的默认值,因此当使用onDelete SET_DEFAULT时,默认值将为NULL,因为尚未设置任何实际默认值。


注意Room现在使用defaultValue()批注中的@ColumnInfo支持默认值。
使用= false不会影响实际的SQLite表,即,如果使用布尔值,则列定义将是labelId INTEGER而不是labelId INTEGER DEFAULT 0


假设NULL是可接受的,则可以使用布尔(对象)而不是布尔(主要类型)。对象可以为null。

即在会话中使用

public Boolean archived = false;


视觉外植

以下是Room为会话实体生成的代码,但使用:-添加了附加列

.........
public boolean archived = false;
public Boolean other_archived = false; //<<<<<<<<<< ADDED
........


房间生成的代码:-

CREATE TABLE IF NOT EXISTS `Session` (
    `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
    `label` TEXT,

    `archived` INTEGER NOT NULL, /*<<<<<<<<<< boolean so NOT NULL */
    `other_archived` INTEGER, /*<<<<<<<<<< Boolean so no NOT NULL */
    FOREIGN KEY(`label`, `archived`) REFERENCES `Label`(`id`, `archived`) ON UPDATE CASCADE ON DELETE SET DEFAULT)




额外

如果希望“会话”表中的存档列为0(假),则必须修改该表。这将需要


创建相同的替换表,除了标签列定义为label INTEGER DEFAULT 0(即添加DEFAULT 0)之外
将数据从会话表复制到替换表,例如INSERT INTO replacement_Session SELECT * FROM Session;
重命名会话表。
将替换表重命名为Session。
如果满意,请删除重命名的Session表。


另外(我认为),您可以使用AFTER UPDATE TRIGGER将NULL更改为0(假)。

必须在Room之外或在RoomDatabase构建之前完成这两种选择。

关于android - session 室数据库:NOT NULL约束删除失败,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58077156/

10-11 22:21
查看更多