我有以下 dao:
@Dao
public interface IncomeRecordWithTypeValueDao extends BaseDao<IncomeRecordWithTypeValue> {
@Query("SELECT * FROM IncomeRecordWithTypeValue")
Flowable<List<IncomeRecordWithTypeValue>> getAll();
}
@Dao
public interface BaseDao<T> {
@Insert(onConflict = OnConflictStrategy.REPLACE)
List<Long> synchronousInsertOrUpdate(List<T> objs);
}
我的 sqlite 表如下所示:
CREATE TABLE "IncomeRecordWithTypeValue" (
"id" INTEGER NOT NULL,
"amount" REAL NOT NULL,
"incomeRecordId" INTEGER NOT NULL,
"incomeTypeId" INTEGER NOT NULL,
FOREIGN KEY("incomeTypeId") REFERENCES "IncomeType"("id") ON DELETE CASCADE,
FOREIGN KEY("incomeRecordId") REFERENCES "IncomeRecord"("id") ON DELETE CASCADE,
PRIMARY KEY("id" AUTOINCREMENT)
)
基本上,我想要用于測驗目的是在表中插入一行,如果它不存在,否則我想更新它。因此,我正在嘗試使用以下陳述句更新所有現有行:
incomeRecordWithTypeValueDao().getAll().subscribe(all -> {
//all returns [IncomeRecordWithTypeValue{id=7, incomeRecordId=7, incomeTypeId=1, amount=55.0}, IncomeRecordWithTypeValue{id=8, incomeRecordId=8, incomeTypeId=1, amount=55.0}]
List<Long> long = incomeRecordWithTypeValueDao().synchronousInsertOrUpdate(all);
}, err -> {
err.printStackTrace();
//returns android.database.sqlite.SQLiteConstraintException: FOREIGN KEY constraint failed (Sqlite code 787 SQLITE_CONSTRAINT_FOREIGNKEY), (OS error - 2:No such file or directory)
});
有什么我想念的嗎。如果我單獨使用插入和更新,它可能會起作用,但我的目標是在一個查詢中使用這兩個函式 (OnConflict.REPLACE)
編輯:
我有以下觸發器:
CREATE TRIGGER Trigger_DeleteIncomeRecAfterExpenseTypeDelete
AFTER DELETE ON IncomeRecordWithTypeValue
BEGIN
DELETE FROM IncomeRecord
WHERE id = OLD.incomeRecordId AND NOT EXISTS(SELECT 1 FROM IncomeRecordWithTypeValue irwtv WHERE irwtv.incomeRecordId = IncomeRecord.id); END
該觸發器會導致問題,因為系統嘗試洗掉收入記錄,然后將值型別添加到由于觸發器而已被洗掉的同一記錄中。
uj5u.com熱心網友回復:
您可以應用這些更改,假設最終結果是不沖突但暫時沖突的 FK 約束,通過使用延遲的外鍵約束。也就是說,約束檢查會一直保留到事務提交為止。
對于 CREATE SQL,您將使用 :-
FOREIGN KEY("incomeTypeId") REFERENCES "IncomeType"("id") ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
FOREIGN KEY("incomeRecordId") REFERENCES "IncomeRecord"("id") ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
見https://sqlite.org/foreignkeys.html#fk_deferred
對于物體,您將deferred = true按照https://developer.android.com/reference/androidx/room/ForeignKey#deferred() 進行編碼
額外的評論/編輯(觸發):-
我發現是什么引起了這個問題。問題是我有一個觸發器(請參閱答案編輯),它會洗掉“收入記錄”,以防所有“值型別”都被洗掉。所以即使使用 deferred 也不會無緣無故地防止外鍵約束問題。也許洗掉觸發器并在代碼中實作觸發器是要走的路。
這里的問題是INSERT OR REPLACE通過洗掉要替換的行然后插入行來作業,從而分配一個新的 rowid或其別名(INTEGER PRIMARY KEY,帶或不帶 AUTOINCREMENET aka autogenerate = true 將導致該列成為行號)。
如果不是INSERT OR REPLACE(onConflict = REPLACE在房間中)使用 INSERT OR IGNORE (onConflict = IGNORE) 并測驗結果(Kotlin 中的 Long),它將是大于 0(插入行)或 -1(未插入行)的正值。
在 -1(或 < 1)的情況下,然后可以呼叫/運行 UPDATE 以執行現有行的更新,從而維護 id 并且也不會意外呼叫 TRIGGER。
- 請注意,以上不會滿足可以使用的負 rowid。然而,使用負的 rowid 是必須的,并且超出了 SQLite 的正常使用范圍。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/403611.html
標籤:
