簡體   English   中英

如何避免房間外鍵錯誤-約束失敗(代碼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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM