SQLite kullanan Android'de yabancı anahtar kısıtlamaları? Basamaklı sil


91

İki tablom var: izler ve ara noktalar, bir iz birçok ara noktaya sahip olabilir, ancak bir yol noktası yalnızca 1 ize atanır.

Nokta tablosunda, bir iz yapıldıktan sonra track_ID'yi ekleyen "trackidfk" adlı bir sütunum var, ancak bu sütunda Yabancı Anahtar kısıtlamaları ayarlamadım.

Bir izi sildiğimde, atanan yol noktalarını silmek istiyorum, bu mümkün mü? Tetikleyicileri kullanmayı okudum, ancak Android'de desteklendiklerini sanmıyorum.

Yol noktaları tablosu oluşturmak için:

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"
                + " );"
              );

    ...
}

Yanıtlar:


237

Silme basamaklı dış anahtar kısıtlamaları desteklenir, ancak bunları etkinleştirmeniz gerekir. İşe yarayacak gibi görünen SQLOpenHelper'ıma
aşağıdakileri ekledim .

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

Referans sütunumu aşağıdaki gibi ilan ettim.

mailbox_id INTEGER REFERENCES mailboxes ON DELETE CASCADE

59
Hangi araçlar sadece SQLite'ı 3.6.22 sahiptir Android 2.2 Froyo beri çalışıyor
Intrications

@RedPlanet - çünkü bu kısıtlamanın uygulandığı tek zaman, veritabanına bir şey yazıldığı zamandır. (Tüm yaptığınız db'den okumaksa bu kısıtlamayı kaldıramazsınız) Ayrıca Phil, onOpen yöntemi yerine, muhtemelen onConfigure yönteminde yapmak daha iyidir. Kaynak: developer.android.com/reference/android/database/sqlite/…
Aneem

12
Google, PRAGMAifadelerin yazılmasını önerir , onConfigure()ancak API düzeyi 16 (Android 4.1) gerektirir ve o zamana kadar kolayca arayabilirsiniz setForeignKeyConstraintsEnabled.
Pang

Daha önce olan onCreate/ onDowngrade/ içindeki yabancı anahtar kısıtlamalarını etkinleştirmeyi de düşünmek gerekebilir . Android 4.1.1'deki kaynak koduna bakın . onUpgradeonOpen
Pang

1
@Natix, süper çağrıyı da içeren, uygulanan sınıf ile üst sınıf arasında bir ara sınıfın tanıtılması durumunda doğru işlevselliği sağlar.
tbm


26

E.shishkin'in gönderisinde belirtildiği gibi API 16'dan itibaren, SqLiteOpenHelper.onConfigure(SqLiteDatabase)yöntemde yabancı anahtar kısıtlamalarını kullanarakdb.setForeignKeyConstraintsEnabled(boolean)

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

10

Daha eksiksiz bir cevapla cevaplamak için asla çok eski bir soru.

@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'de bahsedilen her şey iyidir. Ancak, yabancı anahtarı ayarlamak için Veritabanının kendisinde bulunan başka bir varsayılan yöntemi kullanabilirsiniz. Bu setForeignKeyConstraintsEnabled (true) değeridir.

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

Dokümanlar için SQLiteDatabase.setForeignKeyConstraintsEnabled'a bakın


3
Yayınladığınız dokümantasyon öneriyor: A good time to call this method is right after calling openOrCreateDatabase(File, SQLiteDatabase.CursorFactory) or in the onConfigure(SQLiteDatabase) callback. Yani yerine onOpen, onConfiguredoğru yerde gibi görünüyor.
Paul Woitaschek

4

SQLite'in bunu kutunun dışında desteklediğini sanmıyorum. Uygulamalarımda yaptığım şey:

  1. İşlem oluştur
  2. Ayrıntılı verileri silin (örneğinizdeki ara noktalar)
  3. Ana verileri silin (örneğinizdeki parçalar)
  4. Başarı üzerine işlem gerçekleştirin

Bu şekilde, tüm verilerin silineceğinden veya hiçbirinin silindiğinden eminim.


Ancak her iki tablodan tek bir yöntem kullanarak mı siliyorsunuz?
jcrowson

Evet, API'deki Notes örneğiyle hemen hemen aynı fikirdeyim. Sizin durumunuzda bir izi sileceğim zaman, işlemi oluşturur, yolu ve ara noktaları siler ve işlemi taahhüt ederim. Hepsi tek seferde.
Thorsten Dittmar

4

Tetikleyiciler android tarafından desteklenir ve bu tür kademeli silme sqlite tarafından desteklenmez. Android'de tetikleyicilerin kullanımına bir örnek burada bulunabilir . Thorsten'in belirttiği gibi işlemleri kullanmak muhtemelen bir tetikleyici kadar kolaydır.


3

Android 1.6'daki SQLite sürümü 3.5.9 olduğundan yabancı anahtarları desteklemiyor ...

http://www.sqlite.org/foreignkeys.html "Bu belge, SQLite 3.6.19 sürümünde tanıtılan SQL yabancı anahtar kısıtlamaları için desteği açıklar."

Froyo'da SQLite 3.6.22 sürümü, yani ...

DÜZENLEME: sqlite sürümünü görmek için: adb shell sqlite3 -version


Bu tür kısıtlamaları zorlamanın bir yolu var mı .. Yani, sqlite sürümünü yükseltmenin herhangi bir yolu var mı .. çünkü yukarıdaki gibi sqlite sürümü 3.5.9 olan android 2.1'e yazılım sürümünü desteklemeliyiz
NullPointerException

Hayır, her şeyi kendiniz halletmelisiniz :(
GBouerat

1

"Cascade silme" özelliğine sahip yabancı anahtarlar, Android 2.2 ve sonraki sürümlerde SQLite'da desteklenir. Ancak bunları kullanırken dikkatli olun: bazen bir sütunda bir yabancı anahtarı çalıştırırken bir hata bildirilir, ancak asıl sorun ya alt tablodaki başka bir sütunda yabancı anahtar kısıtlamasında ya da bu tabloya başvuran başka bir tabloda yatmaktadır.

Görünüşe göre SQLite, bunlardan birini çalıştırırken tüm kısıtlamaları kontrol ediyor. Aslında belgelerde bahsedilmektedir. DDL ve DML kısıtlama kontrolleri.


0

Android Room kullanıyorsanız, aşağıda gösterildiği gibi yapın.

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()
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.