Android中使用SQLite的外键约束?在删除级联

时间:2010-03-30 13:32:13

标签: java android sqlite foreign-keys

我有两个表:轨道和航点,轨道可以有多个航点,但航点只分配给一个航迹。

在点数表中,我有一个名为“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"
                + " );"
              );

    ...
}

10 个答案:

答案 0 :(得分:232)

支持使用on delete cascade的外键约束,但您需要启用它们 我刚刚将以下内容添加到我的 SQLOpenHelper 中,这似乎可以解决问题。

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

我声明了我的引用列如下。

mailbox_id INTEGER REFERENCES mailboxes ON DELETE CASCADE

答案 1 :(得分:53)

由于Android 4.1(API 16)SQLiteDatabase支持:

public void setForeignKeyConstraintsEnabled (boolean enable)

答案 2 :(得分:26)

正如e.shishkin的帖子从API 16开始说的那样,您应该使用SqLiteOpenHelper.onConfigure(SqLiteDatabase)

db.setForeignKeyConstraintsEnabled(boolean)方法中启用外键约束
@Override
public void onConfigure(SQLiteDatabase db){
    db.setForeignKeyConstraintsEnabled(true);
}

答案 3 :(得分:9)

从来没有过多的问题要回答更完整的答案。

@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);
}

答案 4 :(得分: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)
    }
}

对于文档,请参阅SQLiteDatabase.setForeignKeyConstraintsEnabled

答案 5 :(得分:4)

我认为SQLite不支持开箱即用。我在我的应用程序中所做的是:

  1. 创建交易
  2. 删除详细数据(示例中的航点)
  3. 删除主数据(示例中的曲目)
  4. 提交成功交易
  5. 这样我确定所有数据都被删除或没有。

答案 6 :(得分:4)

android支持触发器,sqlite不支持该类型的级联删除。可以在here找到在android上使用触发器的示例。虽然像Thorsten所说的那样使用交易可能就像触发一样容易。

答案 7 :(得分:3)

Android 1.6中的SQLite版本是3.5.9所以它不支持外键...

http://www.sqlite.org/foreignkeys.html “本文档描述了对SQLite版本3.6.19中引入的SQL外键约束的支持。”

在Froyo中它是SQLite版本3.6.22,所以......

编辑: 看sqlite版本:adb shell sqlite3 -version

答案 8 :(得分:1)

Android 2.2及更高版本的SQLite支持带有“on delete cascade”的外键。但是在使用它们时要小心:有时在一列上触发一个外键时会报告错误,但真正的问题在于子表中的另一个列外键约束,或者其他一些表引用该表。

看起来SQLite在启动其中一个时检查所有约束。它实际上在文档中提到过。 DDL与DML约束检查。

答案 9 :(得分:0)

如果您使用的是Android Room,请执行以下操作。

Room.databaseBuilder(context, AppDatabase::class.java, DATABASE_NAME)
    .addCallback(object : RoomDatabase.Callback() {
        // Called when the database has been opened.
        override fun onOpen(db: SupportSQLiteDatabase) {
            super.onOpen(db)
            //True to enable foreign key constraints
            db.setForeignKeyConstraintsEnabled(true)
        }

        // Called when the database is created for the first time. 
        override fun onCreate(db: SupportSQLiteDatabase) {
            super.onCreate(db)
        }
    }).build()