SQLiteを使用したAndroidの外部キー制約?カスケードの削除時


91

トラックとウェイポイントの2つのテーブルがあります。トラックには多くのウェイポイントを設定できますが、ウェイポイントは1つのトラックにのみ割り当てられます。

ウェイポイントテーブルには、トラックが作成されるとtrack_IDを挿入する「trackidfk」という列がありますが、この列には外部キー制約を設定していません。

割り当てられたウェイポイントを削除したいトラックを削除した場合、これは可能ですか?トリガーの使用について読みましたが、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"
                + " );"
              );

    ...
}

回答:


237

削除カスケードの外部キー制約はサポートされていますが、有効にする必要があります。
私は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

59
どの手段だけのSQLite 3.6.22持つアンドロイド2.2フローズンヨーグルト以来作品
Intrications

@RedPlanet-これは、この制約が適用されるのはデータベースに何かが書き込まれるときだけだからです。(行うのがデータベースから読み込まれるだけの場合は、この制約を破ることはできません)また、onOpenメソッドの代わりにPhilは、onConfigureメソッドで実行することをお勧めします。出典:developer.android.com/reference/android/database/sqlite/...
Aneem

12
GoogleではでPRAGMAステートメントを記述することを推奨してonConfigure()いますが、APIレベル16(Android 4.1)が必要であり、その時点でを呼び出すだけで済みますsetForeignKeyConstraintsEnabled
2013

一つは、また、中に外部キー制約を有効にすることを検討する必要があるかもしれませんonCreate/ onDowngrade/ onUpgrade、前ですonOpenAndroid 4.1.1のソースコードをご覧ください。
2013

1
スーパーへの呼び出しを含む@Natixは、実装されたクラスとその親の間に中間クラスが導入された場合に正しい機能を保証します。
tbm


26

e.shishkinからの投稿によると、API 16以降では、SqLiteOpenHelper.onConfigure(SqLiteDatabase)メソッドを使用して外部キー制約を有効にする必要があります。db.setForeignKeyConstraintsEnabled(boolean)

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

10

質問が古すぎて、より完全な答えで答えることはできません。

@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. ので、代わりにonOpenonConfigure適切な場所のようです。
Paul Woitaschek 2017年

4

SQLiteはそのままではこれをサポートしていないと思います。私のアプリでやっていることは:

  1. トランザクションを作成
  2. 詳細データ(例ではウェイポイント)を削除します
  3. マスターデータ(例ではトラック)を削除します
  4. 成功時にトランザクションをコミットする

そうすれば、すべてのデータが削除されるか、まったく削除されないことが確実になります。


しかし、1つの方法を使用して両方のテーブルから削除していますか?
jcrowson 2010年

はい、APIのNotesサンプルとほぼ一緒に使用しました。あなたのケースでトラックになるものを削除する場合は、トランザクションを作成し、トラックとウェイポイントを削除して、トランザクションをコミットします。一度ですべてです。
Thorsten Dittmar

4

トリガーはandroidでサポートされており、そのタイプのカスケード削除はsqliteではサポートされていません。Androidでトリガーを使用する例は、こちらにあります。トールステンが述べたようにトランザクションを使用することは、おそらくトリガーと同じくらい簡単です。


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


したがって、そのような制約を強制する方法はあります。つまり、SQLiteのバージョンをアップグレードする方法はあります。上記のように、ソフトウェアのバージョンをsqliteのバージョン3.5.9を持つAndroid 2.1にサポートする必要があるためです
NullPointerException

いいえ、すべてを自分で処理する必要があります:(
GBouerat

1

「カスケード削除時」の外部キーは、Android 2.2以降のSQLiteでサポートされています。ただし、使用時には注意してください。1つの列で1つの外部キーを起動するとエラーが報告されることがありますが、実際の問題は、子テーブルの別の列の外部キー制約、またはこのテーブルを参照する他のテーブルにあります。

SQLiteはそれらの1つを起動するときにすべての制約をチェックするように見えます。それは実際にドキュメントで言及されています。DDLとDMLの制約チェック。


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()
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.