4

我有一個奇怪的問題,在我的android應用程序,它與外鍵上的數據庫關係有關。下面的代碼說明我的簡單數據庫的結構, 我已經使用SQLiteOpenHelper作爲手柄數據庫操作一個超類從Sqlite數據庫表刪除故障(關係非常行爲)

private static final String CATEGORIES_TABLE = "CREATE TABLE __CATEGORIES_TBL(_id INTEGER PRIMARY KEY AUTOINCREMENT, _name TEXT NOT NULL, _desc TEXT NULL," 
        + "_create_date INTEGER NOT NULL, _update_date INTEGER NULL" 
        + ", _parent_id INTEGER NULL, FOREIGN KEY(_parent_id) REFERENCES __CATEGORIES_TBL(_id) ON DELETE RESTRICT);"; 

    private static final String CARDS_TABLE = "CREATE TABLE __CARDS_TBL(_id INTEGER PRIMARY KEY AUTOINCREMENT," 
        + "_value TEXT NOT NULL, _play_count INTEGER NULL, " 
        + "_category_id INTEGER NOT NULL, FOREIGN KEY(_category_id) REFERENCES __CATEGORIES_TBL(_id) ON DELETE RESTRICT);"; 

@Override 
    public void onCreate(SQLiteDatabase db) { 
     try { 
      db.execSQL("PRAGMA foreign_keys = ON;"); 
      db.execSQL(CATEGORIES_TABLE);   
      db.execSQL(CARDS_TABLE); 
      Logger.i("DB-INIT-DONE!"); 
     } catch (Exception ex) { 
      Logger.e("Database on create error", ex); 
     } 

    } 

,你看到的一切似乎是O.K,它是;我可以插入,編輯,從兩個表中選擇行,但不幸的是我可以刪除他們有子行的行。 正如我所料。因爲我使用ON DELETE RESTRICT模式設置了兩個表之間的FK(外鍵)關係,因此我期望在我嘗試從父表中刪除一行時(__CATEGORIES_TBL),實際上父記錄正在刪除並且不會出現異常發生,

理論sqlite必須防止刪除__CATEGORIES_TBL中的任何行__CARDS_TBL中的一個或多個子行或__CATEGORIES_TBL中的任何子行時,但在我的應用程序中,我可以刪除行時,它有一個親子關係行,

考慮下面的代碼(這是刪除代碼)

private SQLiteDatabase db; 
public long delete(long objId) { 
      try { 
          // TABLE_NAME can be __CATEGORIES_TBL or __CARDS_TBL based on program flow 
       return db.delete(TABLE_NAME, COLUMN_ROWID + "=" + objId, null); 
      } catch (Exception e) { 
       Logger.d("Unable to delete category <" + objId + ">.", e); 
       return -123456; 
      } 
     } 

每次調用db.delete都會返回1(表示1行被該命令刪除),這段代碼在android 2.3下執行;

在此先感謝。

+0

你應該可能創建一個觸發器,以避免 –

回答

0

我得到了SQLite 3.7.9期望的行爲。

sqlite> CREATE TABLE __CATEGORIES_TBL ( 
    ...> _id INTEGER PRIMARY KEY AUTOINCREMENT, 
    ...> _name TEXT NOT NULL, 
    ...> _desc TEXT NULL, 
    ...> _create_date INTEGER NOT NULL, 
    ...> _update_date INTEGER NULL, 
    ...> _parent_id INTEGER NULL, 
    ...> FOREIGN KEY(_parent_id) 
    ...> REFERENCES __CATEGORIES_TBL(_id) ON DELETE RESTRICT 
    ...>); 
sqlite> 
sqlite> CREATE TABLE __CARDS_TBL(
    ...> _id INTEGER PRIMARY KEY AUTOINCREMENT, 
    ...> _value TEXT NOT NULL, 
    ...> _play_count INTEGER NULL, 
    ...> _category_id INTEGER NOT NULL, 
    ...> FOREIGN KEY(_category_id) 
    ...>  REFERENCES __CATEGORIES_TBL(_id) ON DELETE RESTRICT 
    ...>); 
sqlite> 
sqlite> insert into __categories_tbl values 
    ...> (1, 'name', 'desc',current_date,current_date,1); 
sqlite> insert into __cards_tbl values (1, 'value',3, 1); 
sqlite> pragma foreign_keys=on; 
sqlite> select * from __categories_tbl; 
1|name|desc|2012-08-25|2012-08-25|1 
sqlite> delete from __categories_tbl; 
Error: foreign key constraint failed 

如果我是你,我會嘗試目視檢查SQLite數據庫每一步之後,看你是否期望什麼發生的是實際發生的事情。 IIRC,並非每一次失敗都會引發一個例外。


在版本3.6.19中引入了外鍵支持。有compile-time settings允許SQLite解析外鍵約束,但不允許它實際執行它們。 (定義了SQLITE_OMIT_TRIGGER,未定義SQLITE_OMIT_FOREIGN_KEY)。您應該能夠判斷您的SQLite構建是否可以通過嘗試創建觸發器來強制執行外鍵。

如果創建觸發器失敗並出現解析錯誤,那麼SQLite將解析外鍵語句,但不會強制執行它們。你需要重新編譯你的3.6.19版本,或者升級到更新的版本。 (並在編譯之前檢查這些設置。)

如果插入空字符串,則聲明NOT NULL的列可能顯示爲空。默認情況下,NULL和空字符串在輸出上看起來完全相同。您可以通過選擇列來判斷列是否包含空值。

select * from table_name where column_name is null; 
+0

你對我已經測試了sqlite的2個版本的sql代碼,第一個是3.6。22我認爲它在這個問題上有一個錯誤,另一個是3.7.4,它正在正常工作。我必須在手機上安裝新版本的sqlite嗎? –

+0

另一個問題是關於表__CARDS_TBL中的字段'_value'它有一個TEXT NOT NULL聲明,所以對這個字段有一個空值的行不能被執行,但在我的應用程序中它正在發生,我不明白這裏有什麼問題? –

+0

@ user1551608:更新了答案。 –

0

關於這個問題我已經把db.execSQL(「pragma foreign_keys = on;」);之前刪除我的應用程序代碼中的語句,然後問題解決了,但我認爲這是不必要的代碼也許我的手機的安裝sqlite配置是錯誤的,需要重新配置,是否有可能重新配置手機上的sqlite? 測試設備是一個HTC Wildfire S(運行SQLite版本是3.7.2)