Ограничения внешнего ключа в Android с использованием SQLite? Удалить каскад

82

У меня есть две таблицы: дорожки и путевые точки, трек может иметь много путевых точек, но путевая точка назначается только одному треку.

В таблице точек таблицы у меня есть столбец с названием "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"
                + " );"
              );

    ...
}
Теги:
foreign-keys

9 ответов

213
Лучший ответ

Ограничения внешнего ключа с помощью каскада delete поддерживаются, но вам необходимо включить их.
Я просто добавил следующее в свой 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
  • 32
    Как комментарий: это работает только с SQLite версии 3.6.19.
  • 58
    Это означает, что он работает только с Android 2.2 Froyo с SQLite 3.6.22
Показать ещё 7 комментариев
51

Так как Android 4.1 (API 16) SQLiteDatabase поддерживает:

public void setForeignKeyConstraintsEnabled (boolean enable)
23

Как говорится в сообщении от e.shishkin из API 16 up, вы должны включить ограничения внешнего ключа в методе SqLiteOpenHelper.onConfigure(SqLiteDatabase), используя db.setForeignKeyConstraintsEnabled(boolean)

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

Никогда не слишком старый вопрос, чтобы ответить с более полным ответом.

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

  • 3
    A good time to call this method is right after calling openOrCreateDatabase(File, SQLiteDatabase.CursorFactory) or in the onConfigure(SQLiteDatabase) callback. вами документация предлагает: A good time to call this method is right after calling openOrCreateDatabase(File, SQLiteDatabase.CursorFactory) or in the onConfigure(SQLiteDatabase) callback. Таким образом, вместо onOpen , onConfigure кажется правильным местом.
4

Я не думаю, что SQLite поддерживает это из коробки. Что я делаю в своих приложениях:

  • Создать транзакцию
  • Удалить подробные данные (путевые точки в вашем примере)
  • Удалить основные данные (дорожки в вашем примере)
  • Зафиксировать транзакцию при успешном завершении

Таким образом, я уверен, что либо все данные удалены, либо нет.

  • 0
    Но вы удаляете из обеих таблиц одним методом?
  • 0
    Да, я в значительной степени согласился с примером Notes из API. Когда я должен удалить трек в вашем случае, я создаю транзакцию, удаляю трек и путевые точки и фиксирую транзакцию. Это все за один раз.
4

Триггеры поддерживаются андроидом, и этот тип каскадного удаления не поддерживается sqlite. Пример использования триггеров на Android можно найти здесь здесь. Хотя использование транзакций, как утверждал Торстен, возможно, так же просто, как триггер.

3

Версия SQLite в android 1.6 - 3.5.9, поэтому она не поддерживает внешние ключи...

http://www.sqlite.org/foreignkeys.html "В этом документе описывается поддержка ограничений внешнего ключа SQL, введенных в SQLite версии 3.6.19".

В Froyo это SQLite версии 3.6.22, поэтому...

EDIT: для просмотра версии sqlite: adb shell sqlite3 -version

  • 0
    Так есть ли способ заставить такие ограничения .. Я имею в виду, есть ли способ обновить версию sqlite .. потому что мы должны поддерживать версию программного обеспечения для Android 2.1, который имеет версию 3.5.9 sqlite, как указано выше
  • 0
    Нет, ты должен все уладить самостоятельно :(
1

Внешние ключи с "on delete cascade" поддерживаются в SQLite в Android 2.2 и выше. Но будьте осторожны при их использовании: иногда возникает ошибка при запуске одного внешнего ключа в одном столбце, но реальная проблема заключается в любом другом внешнем ключевом ограничении в дочерней таблице, или какая-либо другая таблица тета ссылается на эту таблицу.

Похоже, SQLite проверяет все ограничения при запуске одного из них. Это фактически упоминается в документации. Проверки ограничений DDL и DML.

Сообщество Overcoder
Наверх
Меню