SQLite外键约束失败(代码787)

时间:2015-03-30 08:17:47

标签: android sqlite foreign-keys foreign-key-relationship

我尝试升级数据库时遇到Foreign Key Constraint Failed (code 787)错误。我做的唯一改变是尝试在InsertStatus添加第4个条目。我环顾四周,我读到使用ON DELETE CASCADE应该解决我的问题,所以我尝试将它放在我所有的FK引用上并再次尝试,但仍然是同样的问题。

Logcat指向我的onUpgrade以及其中的所有DROP TABLES(我尝试一次删除一个,看看哪些是坏的,显然所有都是坏的)。

我使用ON DELETE CASCADE错了吗?或者我的代码中还有其他内容?

InsertStatus

void InsertStatus(SQLiteDatabase db) {
    ContentValues cv = new ContentValues();
    cv.put(colStatusID, 0);
    cv.put(colStatClass, "Active");
    db.insert(statTable, colStatusID, cv);
    cv.put(colStatusID, 1);
    cv.put(colStatClass, "Settled");
    db.insert(statTable, colStatusID, cv);
    cv.put(colStatusID, 2);
    cv.put(colStatClass, "Terminated");
    db.insert(statTable, colStatusID, cv);
    cv.put(colStatusID, 3);
    cv.put(colStatClass, "");
    db.insert(statTable, colStatusID, cv);
}

DatabaseHelper

db.execSQL("CREATE TABLE " + termsTable + " (" + colTermsID + " INTEGER PRIMARY KEY , " + colTermsClass + " TEXT)");

    db.execSQL("CREATE TABLE " + periodTable + " (" + colPeriodID + " INTEGER PRIMARY KEY , " + colPeriodClass + " TEXT)");

    db.execSQL("CREATE TABLE " + statTable + " (" + colStatusID + " INTEGER PRIMARY KEY , " + colStatClass + " TEXT)");

    db.execSQL("CREATE TABLE " + accountsTable + " (" + colID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
            colName + " TEXT, " +
            colAmount + " Integer, " +
            colPurpose + " TEXT, " +
            colTerms + " INTEGER NOT NULL, " +
            colPeriod +" INTEGER NOT NULL, " +
            colBalance +" INTEGER, "+
            colStatus + " INTEGER DEFAULT '1'," +
            colDate + " TEXT, " +
            colEditDate + " TEXT, " +
            "FOREIGN KEY (" + colTerms + ") REFERENCES " + termsTable + " (" + colTermsID + ") ON DELETE CASCADE," +
            "FOREIGN KEY (" + colPeriod + ") REFERENCES " + periodTable + " (" + colPeriodID + ") ON DELETE CASCADE," +
            "FOREIGN KEY (" + colStatus + ") REFERENCES " + statTable + " (" + colStatusID + ") ON DELETE CASCADE);");

    db.execSQL("CREATE TABLE " + payTable + " (" + colPayID + " INTEGER PRIMARY KEY , " +
            colGroupID + " INTEGER NOT NULL, " +
            colPayBal + " TEXT, " +
            colInterest + " TEXT, " +
            colPayDue + " TEXT, " +
            colDateDue + " TEXT, " +
            colPaid + " Integer, " +
            "FOREIGN KEY (" + colGroupID + ") REFERENCES " + accountsTable + " (" + colID + ") ON DELETE CASCADE);");

    db.execSQL("CREATE VIEW " + viewAccs +
            " AS SELECT " + accountsTable + "." + colID + " AS _id," +
            " " + accountsTable + "." + colName + "," +
            " " + accountsTable + "." + colAmount + "," +
            " " + accountsTable + "." + colPurpose + "," +
            " " + termsTable + "." + colTermsClass + "," +
            " " + periodTable + "." + colPeriodClass + "," +
            " " + accountsTable+ "." + colBalance + "," +
            " " + statTable + "." + colStatClass + "," +
            " " + accountsTable + "." + colDate + "," +
            " " + accountsTable + "." + colEditDate + "" +
            " FROM " + accountsTable +
            " JOIN " + termsTable + " ON " + accountsTable + "." + colTerms + " = " + termsTable + "." + colTermsID +
            " JOIN " + periodTable + " ON " + accountsTable + "." + colPeriod + " = " + periodTable + "." + colPeriodID +
            " JOIN " + statTable + " ON " + accountsTable + "." + colStatus + " = " + statTable + "." + colStatusID );

    db.execSQL("CREATE VIEW " + viewPmnts +
            " AS SELECT " + payTable + "." + colPayID + " AS _id," +
            " " + accountsTable + "." + colID + "," +
            " " + payTable + "." + colGroupID + "," +
            " " + payTable + "." + colPayBal + "," +
            " " + payTable + "." + colInterest + "," +
            " " + payTable + "." + colPayDue + "," +
            " " + payTable + "." + colDateDue + "," +
            " " + payTable + "." + colPaid + "" +
            " FROM " + payTable +
            " JOIN " + accountsTable + " ON " + payTable + "." + colGroupID + " = " + accountsTable + "." + colID );

    InsertTerms(db);
    InsertPeriods(db);
    InsertStatus(db);
}

onUpgrade

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {


    db.execSQL("DROP TABLE IF EXISTS " + accountsTable);
    db.execSQL("DROP TABLE IF EXISTS " + termsTable);
    db.execSQL("DROP TABLE IF EXISTS " + periodTable);
    db.execSQL("DROP TABLE IF EXISTS " + statTable);
    db.execSQL("DROP TABLE IF EXISTS " + payTable);

    db.execSQL("DROP TRIGGER IF EXISTS acc_id_trigger");
    db.execSQL("DROP TRIGGER IF EXISTS acc_id_trigger22");
    db.execSQL("DROP TRIGGER IF EXISTS fk_accterm_termid");
    db.execSQL("DROP TRIGGER IF EXISTS fk_accperiod_periodid");
    db.execSQL("DROP TRIGGER IF EXISTS fk_accpay_payid");
    db.execSQL("DROP TRIGGER IF EXISTS fk_accstat_statid");

    db.execSQL("DROP VIEW IF EXISTS " + viewAccs);
    db.execSQL("DROP VIEW IF EXISTS " + viewPmnts);

    onCreate(db);
}

6 个答案:

答案 0 :(得分:8)

根据以下链接,您插入未通过外键约束的值意味着您添加了父表中不存在的foregin键值

https://www.sqlite.org/foreignkeys.html

答案 1 :(得分:2)

此处的错误与在父级存在之前创建子级实体有关。

流应为:

-创建父级并获取父级ID。 ----创建包含对父ID的引用的子实体。

因此,如果您在未先具有有效父代ID的情况下创建子实体,则会引发此致命错误。

答案 2 :(得分:1)

就我而言,我忘记用数据填充父表。将项目添加到子表时,出现此错误。当删除实体文件中的bfg --delete-files YOUR-FILE-WITH-UNWANTED-DATA 行时:

foreignKeys

插入成为可能。 (但是,如果您这样做却不清除应用程序数据,则会出现异常foreignKeys = [ ForeignKey(entity = SomeEntity::class, parentColumns = ["id"], childColumns = ["parent_id"]), ... ]

因此,只需将必要的数据添加到父表中即可。

更新

我又遇到了这个异常。

为了测试哪个外键冲突,请注释其中几个并重新编译应用程序。还要删除已安装的文件或擦除其数据。启动应用程序后,照常执行请求。如果没有异常,请取消注释一个外键。然后再次删除该应用程序,重新编译,然后将数据添加到表中。直到知道违反哪个外键为止。

在我的情况下,我在列中插入了java.lang.IllegalStateException: Room cannot verify the data integrity. Looks like you've changed schema but forgot to update the version number. You can simply fix this by increasing the version number.而不是0,以便父表不包含null

答案 3 :(得分:0)

确保首先插入父表中的对象。在进行一些测试时,我在犯同样的错误(没有添加相应的父项,因此父表中的PK不存在。)

希望能解决您的问题。

答案 4 :(得分:0)

在我的情况下,问题是我使用了

@Insert(onConflict = OnConflictStrategy.REPLACE)

代替

@Update

在@Dao中。

答案 5 :(得分:0)

获取错误“外键约束失败(代码787)”的另一种方法是,如果表“ Alpha”具有指向表“ Beta”的外键,并且您尝试在Alpha数据之前删除Beta的数据。应该向后做。