如何避免房间外键错误 - 约束失败(代码 787)
How to avoid room foreign key error - constraint failed (code 787)
我有 3 个实体 - 1 个 child 和 2 个 parent。
2 parent个实体可能有很多child个实体,每个人都有自己的。
这是child:
@Entity(
tableName = "share",
foreignKeys = [
ForeignKey(
entity = Pool::class,
childColumns = ["entity_id"],
parentColumns = ["id"],
onDelete = CASCADE
),
ForeignKey(
entity = Note::class,
childColumns = ["entity_id"],
parentColumns = ["id"],
onDelete = CASCADE
)
]
)
data class Share(
@ColumnInfo(name = "share_id")
@PrimaryKey(autoGenerate = false)
val shareId: String,
@ColumnInfo(name = "entity_id")
val entityId: String,
@ColumnInfo(name = "entityType")
val entityType: Int
)
这是 parents:
@Entity(tableName = "pool")
data class Pool(
@PrimaryKey(autoGenerate = false)
@ColumnInfo(name = "id")
val poolId: String,
@ColumnInfo(name = "category")
val type: Int
)
@Entity(tableName = "note")
data class Note(
@PrimaryKey(autoGenerate = false)
@ColumnInfo(name = "id")
val noteId: String
)
Pool和Note可以有多个Share,不相交,每个Share都有自己的独特性。
但是当我尝试保存分享时出现下一个错误:
W/System.err: android.database.sqlite.SQLiteConstraintException: FOREIGN KEY constraint failed (code 787)
W/System.err: at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
W/System.err: at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:783)
W/System.err: at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788)
W/System.err: at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86)
W/System.err: at android.arch.persistence.db.framework.FrameworkSQLiteStatement.executeInsert(FrameworkSQLiteStatement.java:50)
W/System.err: at android.arch.persistence.room.EntityInsertionAdapter.insertAndReturnIdsList(EntityInsertionAdapter.java:243)
W/System.err: at com.my_app.data.db.dao.share.ShareDao_Impl.insertShare(ShareDao_Impl.java:114)
如何避免这个错误?
一个字段不能引用两个外键。在您的设置中,您声明 "entity_id" 是 Pool 类型的外键,父列是 Pool.id 并且 "entity_id" 是 Note 类型的外键,父列是 Note.id.这是一个无效的约束。
您需要在共享 table 中添加一个新列,该列将引用备注 table 作为外键。添加新字段,即 "note_id" 类型的字符串并将其注释为注释 class 的外键。像这样:
@Entity(
tableName = "share",
foreignKeys = [
ForeignKey(
entity = Pool::class,
childColumns = ["entity_id"],
parentColumns = ["id"],
onDelete = CASCADE
),
ForeignKey(
entity = Note::class,
childColumns = ["note_id"],
parentColumns = ["id"],
onDelete = CASCADE
)
]
)
data class Share(
@ColumnInfo(name = "share_id")
@PrimaryKey(autoGenerate = false)
val shareId: String,
@ColumnInfo(name = "entity_id")
val entityId: String,
@ColumnInfo(name = "entityType")
val entityType: Int,
@ColumnInfo(name = "note_id")
val noteId: String
)
我不确定您的数据库结构,但我不知道该应用程序背后的想法,因此无法对结构发表评论。不过,我可以给你一个提示:如果可能的话,使用整数而不是字符串作为主键 - 它可以使数据库操作更快。
希望这个回答对您有所帮助:)
您似乎正试图将两个外键约束放在同一列 (entityId) 上。奇怪的是,SQLite 将允许您使用此设置创建 table。但是,当您添加新行时,它将检查其外键约束以验证该值是否存在于其他 table(s) 中。因此,为了使其成功,您需要在两个 tables:
中都有 entityId
Pool
1|pool1
2|pool2
Note
1|note1
如果我创建一个 entityId = 1 的新共享,这将会成功,因为我有一个 id=1 的池和一个 id=1 的注释。
但是如果我尝试创建 entityId = 2 的共享,外部约束验证将失败,因为没有 id=2 的注释。
您需要重新考虑 table 的结构,以免同一列上有多个外键,可能带有链接 table.
您可以在 SQLite 中进行测试:
PRAGMA foreign_keys=true;
CREATE TABLE pool (id INTEGER PRIMARY KEY, name TEXT);
CREATE TABLE note (id INTEGER PRIMARY KEY, name TEXT);
CREATE TABLE share (id INTEGER PRIMARY KEY, entityId INTEGER, FOREIGN KEY(entityId) REFERENCES pool(id), FOREIGN KEY(entityId) REFERENCES note(id));
insert into pool (name) values ('pool1');
insert into pool (name) values ('pool2');
insert into note (name) values ('note1');
select * from pool;
1|pool1
2|pool2
select * from note;
1|note1
insert into share (entityId) values (1);
insert into share (entityId) values (2);
Error: FOREIGN KEY constraint failed
我有 3 个实体 - 1 个 child 和 2 个 parent。 2 parent个实体可能有很多child个实体,每个人都有自己的。
这是child:
@Entity(
tableName = "share",
foreignKeys = [
ForeignKey(
entity = Pool::class,
childColumns = ["entity_id"],
parentColumns = ["id"],
onDelete = CASCADE
),
ForeignKey(
entity = Note::class,
childColumns = ["entity_id"],
parentColumns = ["id"],
onDelete = CASCADE
)
]
)
data class Share(
@ColumnInfo(name = "share_id")
@PrimaryKey(autoGenerate = false)
val shareId: String,
@ColumnInfo(name = "entity_id")
val entityId: String,
@ColumnInfo(name = "entityType")
val entityType: Int
)
这是 parents:
@Entity(tableName = "pool")
data class Pool(
@PrimaryKey(autoGenerate = false)
@ColumnInfo(name = "id")
val poolId: String,
@ColumnInfo(name = "category")
val type: Int
)
@Entity(tableName = "note")
data class Note(
@PrimaryKey(autoGenerate = false)
@ColumnInfo(name = "id")
val noteId: String
)
Pool和Note可以有多个Share,不相交,每个Share都有自己的独特性。
但是当我尝试保存分享时出现下一个错误:
W/System.err: android.database.sqlite.SQLiteConstraintException: FOREIGN KEY constraint failed (code 787)
W/System.err: at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
W/System.err: at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:783)
W/System.err: at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788)
W/System.err: at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86)
W/System.err: at android.arch.persistence.db.framework.FrameworkSQLiteStatement.executeInsert(FrameworkSQLiteStatement.java:50)
W/System.err: at android.arch.persistence.room.EntityInsertionAdapter.insertAndReturnIdsList(EntityInsertionAdapter.java:243)
W/System.err: at com.my_app.data.db.dao.share.ShareDao_Impl.insertShare(ShareDao_Impl.java:114)
如何避免这个错误?
一个字段不能引用两个外键。在您的设置中,您声明 "entity_id" 是 Pool 类型的外键,父列是 Pool.id 并且 "entity_id" 是 Note 类型的外键,父列是 Note.id.这是一个无效的约束。
您需要在共享 table 中添加一个新列,该列将引用备注 table 作为外键。添加新字段,即 "note_id" 类型的字符串并将其注释为注释 class 的外键。像这样:
@Entity(
tableName = "share",
foreignKeys = [
ForeignKey(
entity = Pool::class,
childColumns = ["entity_id"],
parentColumns = ["id"],
onDelete = CASCADE
),
ForeignKey(
entity = Note::class,
childColumns = ["note_id"],
parentColumns = ["id"],
onDelete = CASCADE
)
]
)
data class Share(
@ColumnInfo(name = "share_id")
@PrimaryKey(autoGenerate = false)
val shareId: String,
@ColumnInfo(name = "entity_id")
val entityId: String,
@ColumnInfo(name = "entityType")
val entityType: Int,
@ColumnInfo(name = "note_id")
val noteId: String
)
我不确定您的数据库结构,但我不知道该应用程序背后的想法,因此无法对结构发表评论。不过,我可以给你一个提示:如果可能的话,使用整数而不是字符串作为主键 - 它可以使数据库操作更快。
希望这个回答对您有所帮助:)
您似乎正试图将两个外键约束放在同一列 (entityId) 上。奇怪的是,SQLite 将允许您使用此设置创建 table。但是,当您添加新行时,它将检查其外键约束以验证该值是否存在于其他 table(s) 中。因此,为了使其成功,您需要在两个 tables:
中都有 entityIdPool
1|pool1
2|pool2
Note
1|note1
如果我创建一个 entityId = 1 的新共享,这将会成功,因为我有一个 id=1 的池和一个 id=1 的注释。
但是如果我尝试创建 entityId = 2 的共享,外部约束验证将失败,因为没有 id=2 的注释。
您需要重新考虑 table 的结构,以免同一列上有多个外键,可能带有链接 table.
您可以在 SQLite 中进行测试:
PRAGMA foreign_keys=true;
CREATE TABLE pool (id INTEGER PRIMARY KEY, name TEXT);
CREATE TABLE note (id INTEGER PRIMARY KEY, name TEXT);
CREATE TABLE share (id INTEGER PRIMARY KEY, entityId INTEGER, FOREIGN KEY(entityId) REFERENCES pool(id), FOREIGN KEY(entityId) REFERENCES note(id));
insert into pool (name) values ('pool1');
insert into pool (name) values ('pool2');
insert into note (name) values ('note1');
select * from pool;
1|pool1
2|pool2
select * from note;
1|note1
insert into share (entityId) values (1);
insert into share (entityId) values (2);
Error: FOREIGN KEY constraint failed