2010-03-30 257 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); 
}