Ограничения внешнего ключа в Android с использованием SQLite? Удалить каскад
У меня есть две таблицы: дорожки и путевые точки, дорожка может иметь много путевых точек, но путевая точка назначается только одной дорожке.
В таблице путевых точек у меня есть столбец с именем "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"
+ " );"
);
...
}
9 ответов
Поддерживаются ограничения внешнего ключа с помощью каскада удаления, но их необходимо включить.
Я просто добавил следующее в свой 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
Начиная с Android 4.1 (API 16) SQLiteDatabase поддерживает:
public void setForeignKeyConstraintsEnabled (boolean enable)
Как говорится в посте от e.shishkin, начиная с API 16, вы должны включить ограничения внешнего ключа в SqLiteOpenHelper.onConfigure(SqLiteDatabase)
метод с использованием db.setForeignKeyConstraintsEnabled(boolean)
@Override
public void onConfigure(SQLiteDatabase db){
db.setForeignKeyConstraintsEnabled(true);
}
Никогда не слишком старый вопрос, чтобы ответить более полным ответом.
@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);
}
Что бы ни упоминал @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
Триггеры поддерживаются Android, и этот тип каскадного удаления не поддерживается sqlite. Пример использования триггеров на Android можно найти здесь. Хотя использование транзакций, как заявил Торстен, вероятно, так же просто, как триггер.
Я не думаю, что SQLite поддерживает это из коробки. Что я делаю в своих приложениях:
- Создать транзакцию
- Удалить подробные данные (путевые точки в вашем примере)
- Удалить основные данные (треки в вашем примере)
- Подтвердить транзакцию в случае успеха
Таким образом, я уверен, что либо все данные удалены, либо нет.
Версия SQLite в Android 1.6 3.5.9, поэтому он не поддерживает внешние ключи...
http://www.sqlite.org/foreignkeys.html"В этом документе описывается поддержка ограничений внешнего ключа SQL, введенных в SQLite версии 3.6.19".
В Froyo это SQLite версии 3.6.22, так что...
РЕДАКТИРОВАТЬ: чтобы увидеть версию sqlite: adb shell sqlite3 -версия
Внешние ключи с "каскадом удаления" поддерживаются в SQLite в Android 2.2 и выше. Но будьте осторожны при их использовании: иногда сообщается об ошибке при запуске одного внешнего ключа в одном столбце, но реальная проблема заключается либо в ограничении внешнего ключа другого столбца в дочерней таблице, либо в какой-либо другой таблице, ссылающейся на эту таблицу.
Похоже, SQLite проверяет все ограничения при запуске одного из них. Это на самом деле упоминается в документации. DDL против проверок ограничений DML.
Если вы используете 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()