2010-03-30 249 views
84

我有兩個表:軌道和航點,一個軌道可以有許多航點,但一個航點只分配到一個軌道。使用SQLite的Android中的外鍵約束?在刪除級聯

在路點表中,我有一個名爲「trackidfk」的列,它在創建軌道後插入track_ID,但是我沒有在該列上設置外鍵約束。

當我刪除一個軌道我想刪除指定的航點,這是可能的嗎?我閱讀了關於使用觸發器,但我不認爲它們在Android中受支持。

要創建航點表:

public void onCreate(SQLiteDatabase db) { 
    db.execSQL("CREATE TABLE " + TABLE_NAME 
       + " (" 
       + _ID   + " INTEGER PRIMARY KEY AUTOINCREMENT, " 
       + LONGITUDE + " INTEGER," 
       + LATITUDE + " INTEGER," 
       + TIME  + " INTEGER," 
       + TRACK_ID_FK + " INTEGER" 
       + ");" 
      ); 

    ... 
} 

回答

229

支持使用刪除級聯的外鍵約束,但您需要啓用它們。
我剛剛將以下內容添加到我的SQLOpenHelper,這似乎是個伎倆。

@Override 
public void onOpen(SQLiteDatabase db) { 
    super.onOpen(db); 
    if (!db.isReadOnly()) { 
     // Enable foreign key constraints 
     db.execSQL("PRAGMA foreign_keys=ON;"); 
    } 
} 

我聲明瞭我的引用列如下。在Android 1.6的

mailbox_id INTEGER REFERENCES mailboxes ON DELETE CASCADE 
+32

作爲一個評論:這隻適用於自sqlite版本3.6.19。 – VansFannel 2010-10-21 12:46:53

+58

這意味着它僅適用於Android 2.2 Froyo,它具有SQLite 3.6.22 – Intrications 2011-01-24 12:13:20

+2

@Phil,爲什麼要使用if-read-only的條件? – 2013-04-26 16:34:48

4

我不認爲SQLite支持這個開箱即用。我在做什麼我的應用程序是:

  1. 創建交易(在你的例子曲目)(在你的例子航點)
  2. 刪除詳細數據
  3. 刪除主數據
  4. 成功
  5. 提交交易

這樣我確信所有的數據都被刪除或沒有。

+0

但是你是否正在使用一種方法從兩個表中刪除? – jcrowson 2010-03-30 14:31:05

+0

是的,我幾乎與API的Notes樣本一起工作。當我要刪除您的案例中的軌道時,我創建交易,刪除軌道和航點並提交交易。這一切都一氣呵成。 – 2010-03-30 14:47:49

4

觸發器由android支持,並且該類型的級聯刪除不被sqlite支持。在android上使用觸發器的示例可以發現here。儘管如Thorsten所說的使用交易可能與觸發器一樣容易。

3

SQLite的版本是3.5.9所以它不支持外鍵...

http://www.sqlite.org/foreignkeys.html 「這個文件描述了SQLite的3.6版推出了SQL外鍵約束的支持。 19.」

在升級Froyo這是SQLite的版本3.6.22,所以......

編輯: 看到sqlite的版本:亞行外殼sqlite3的-version

+0

所以有什麼辦法強制這樣的約束..我的意思是有任何方式來升級sqlite版本..因爲我們必須支持軟件版本到Android 2.1其中有sqlite版本3.5.9如上 – NullPointerException 2012-05-23 12:11:33

+0

不,你有自己處理一切:( – GBouerat 2012-05-29 15:35:29

1

與 「ON DELETE CASCADE」 外鍵SQLite中支持在Android 2.2以上。但是,在使用它們時要小心:有時在一列上啓動一個外鍵時會報告錯誤,但真正的問題在於子表中的另一列外鍵約束或其他表引用此表。

看起來像SQLite在啓動其中一個時會檢查所有約束。它實際上在文檔中提到。 DDL與DML約束檢查。

51

自Android 4以來。1(API 16)SQLiteDatabase支持:

public void setForeignKeyConstraintsEnabled (boolean enable) 
25

由於從e.shishkin職位從API 16說起來,你應該能夠在SqLiteOpenHelper.onConfigure(SqLiteDatabase)方法外鍵約束使用db.setForeignKeyConstraintsEnabled(boolean)

@Override 
public void onConfigure(SQLiteDatabase db){ 
    db.setForeignKeyConstraintsEnabled(true); 
} 
6

無論@phil提到的很好。但是您可以使用 數據庫本身的其他默認方法來設置外鍵。這是setForeignKeyConstraintsEnabled(true)。

@Override 
public void onOpen(SQLiteDatabase db) { 
    super.onOpen(db); 
    if (!db.isReadOnly()) { 
     // Enable foreign key constraints 
     db.execSQL("PRAGMA foreign_keys=ON;"); 
       //(OR) 
     db.setForeignKeyConstraintsEnabled (true) 
    } 
} 

Google文檔的參考SQLiteDatabase.setForeignKeyConstraintsEnabled

+2

您發佈的文檔建議: '一個很好的時間是調用openOrCreateDatabase(文件,SQLiteDatabase.CursorFactory)之後調用此方法或onConfigure(SQLiteDatabase)callback.' 所以不是'onOpen','onConfigure'似乎是正確的地方。 – 2017-06-02 13:47:22

8

學到老問題的一個更完整的答案來回答。

@Override public void onOpen(SQLiteDatabase db) { 
    super.onOpen(db); 
    if (!db.isReadOnly()) { 
     setForeignKeyConstraintsEnabled(db); 
    } 
    mOpenHelperCallbacks.onOpen(mContext, db); 
} 

private void setForeignKeyConstraintsEnabled(SQLiteDatabase db) { 
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { 
     setForeignKeyConstraintsEnabledPreJellyBean(db); 
    } else { 
     setForeignKeyConstraintsEnabledPostJellyBean(db); 
    } 
} 

private void setForeignKeyConstraintsEnabledPreJellyBean(SQLiteDatabase db) { 
    db.execSQL("PRAGMA foreign_keys=ON;"); 
} 

@TargetApi(Build.VERSION_CODES.JELLY_BEAN) 
private void setForeignKeyConstraintsEnabledPostJellyBean(SQLiteDatabase db) { 
    db.setForeignKeyConstraintsEnabled(true); 
}