[英]Android Room error:FOREIGN KEY constraint failed (code 787)
[英]How to avoid room foreign key error - constraint failed (code 787)
我有3個實體-1個孩子和2個父母。 2個父實體可能有許多子實體,每個人都有自己的。
這是孩子:
@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
)
這是父母:
@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可以具有多個不相交的共享,它們各自具有自己的唯一性。
但是,當我嘗試保存共享時,出現下一個錯誤:
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”是Notes類型的外鍵,其父列是Note.id。 這是無效的約束。
您將需要在Share表中添加一個新列,該列將Note表作為外鍵引用。 添加新字段,即String類型的“ note_id”,並將其注釋為Note類的外鍵。 像這樣:
@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將允許您使用此設置創建表。 但是,當您添加新行時,它將檢查其外鍵約束以驗證該值是否存在於其他表中。 因此,為了使此操作成功,您需要在兩個表中都包含entityId:
Pool
1|pool1
2|pool2
Note
1|note1
如果我創建一個具有entityId = 1的新份額,這將成功,因為我有一個id = 1的池和一個id = 1的便箋。
但是,如果我嘗試創建一個entityId = 2的共享,則外部約束驗證將失敗,因為沒有注釋為id = 2。
您需要重新考慮表的結構,以便在同一列上沒有多個外鍵,可能沒有鏈接表。
您可以在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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.