我有以下实体Session
和Label
:
@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;
}
删除附加到
Label
的Session
时,我得到的是NOT NULL constraint failed
的Session.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/