Ошибка внешнего ключа SQLite (код 787)

При попытке обновить мою базу данных я столкнулся с ошибкой, Foreign Key Constraint Failed (code 787) с Foreign Key Constraint Failed (code 787). Единственное изменение, которое я сделал, это попытаться добавить InsertStatus запись в мой InsertStatus. Я огляделся, и я прочитал, что использование 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);
}

Ответ 1

В соответствии с приведенной ниже ссылкой вы вставляете значение, которое не соответствовало ограничениям внешнего ключа, означает, что вы добавили значение ключа foregin, который не существует в родительской таблице

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

Ответ 2

Ошибка здесь связана с созданием дочерней сущности до того, как ее родитель существует.

Поток должен быть:

--Create Родитель и получить родительский идентификатор. ---- Создать дочернюю сущность, содержащую ссылку на родительский идентификатор.

Поэтому, если вы создадите дочернюю сущность, не имея сначала действительного родительского идентификатора, вы получите эту фатальную ошибку.

Ответ 3

В моем случае я забыл заполнить родительскую таблицу данными. Когда добавили элемент в дочернюю таблицу, появилась эта ошибка. При удалении строки foreignKeys в Entity файле:

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 в столбец, чтобы родительская таблица не содержала 0.

Ответ 4

Убедитесь, что вы сначала вставили объект, который находится в родительской таблице. Я делал ту же ошибку при выполнении некоторых тестов (не добавляя соответствующего родителя, так что PK из родительской таблицы не было.)

Ответ 5

В моей ситуации проблема заключалась в том, что я использовал

@Insert(onConflict = OnConflictStrategy.REPLACE)

вместо

@Update

в @Dao.