Ràng buộc khóa ngoại trong Android bằng SQLite? trên Xóa thác


91

Tôi có hai bảng: đường đi và điểm tham chiếu, một đường đi có thể có nhiều điểm tham chiếu, nhưng một điểm tham chiếu chỉ được gán cho 1 đường đi.

Trong bảng cách điểm, tôi có một cột được gọi là "trackidfk" chèn track_ID khi một bản nhạc được tạo, tuy nhiên, tôi chưa thiết lập các ràng buộc Khóa ngoại trên cột này.

Khi tôi xóa một tuyến đường, tôi muốn xóa các điểm tham chiếu đã chỉ định, điều này có khả thi không ?. Tôi đã đọc về cách sử dụng Trình kích hoạt nhưng tôi không nghĩ rằng chúng được hỗ trợ trong Android.

Để tạo bảng điểm tham chiếu:

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

    ...
}

Câu trả lời:


237

Các ràng buộc khóa ngoại với khi xóa tầng được hỗ trợ, nhưng bạn cần phải kích hoạt chúng.
Tôi vừa thêm phần sau vào SQLOpenHelper của mình , điều này dường như thực hiện được thủ thuật.

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

Tôi đã khai báo cột tham chiếu của mình như sau.

mailbox_id INTEGER REFERENCES mailboxes ON DELETE CASCADE

59
Có nghĩa là nó chỉ hoạt động kể từ Android 2.2 Froyo trong đó có SQLite 3.6.22
Intrications

@RedPlanet - đó là vì lần duy nhất ràng buộc này được thực thi là khi một thứ gì đó được ghi vào cơ sở dữ liệu. (Bạn không thể phá vỡ ràng buộc này nếu tất cả những gì bạn làm được đọc từ db) Ngoài ra, Phil, thay vì phương thức onOpen, có lẽ tốt hơn nên làm điều đó trong phương thức onConfigure. Nguồn: developer.android.com/reference/android/database/sqlite/…
Aneem

12
Google khuyên bạn nên ghi các PRAGMAcâu lệnh vào onConfigure()nhưng nó yêu cầu API cấp 16 (Android 4.1) và sau đó bạn có thể chỉ cần gọi setForeignKeyConstraintsEnabled.
Pang

Người ta cũng có thể cần xem xét việc kích hoạt các ràng buộc khóa ngoại trong onCreate/ onDowngrade/ onUpgrade, đã có trước đây onOpen. Xem mã nguồn trong Android 4.1.1 .
Pang

1
@Natix bao gồm lời gọi tới super đảm bảo chức năng chính xác nếu một lớp trung gian được giới thiệu giữa lớp được triển khai và lớp cha của nó.
tbm


26

Như bài đăng từ e.shishkin cho biết từ API 16 trở lên, bạn nên bật các ràng buộc khóa ngoại trong SqLiteOpenHelper.onConfigure(SqLiteDatabase)phương thức bằng cách sử dụngdb.setForeignKeyConstraintsEnabled(boolean)

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

10

Không bao giờ là quá cũ của một câu hỏi để trả lời với một câu trả lời đầy đủ hơn.

@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

Bất cứ điều gì @phil đề cập đều tốt. Nhưng bạn có thể sử dụng một phương pháp mặc định khác có sẵn trong chính Cơ sở dữ liệu để đặt khóa ngoại. Đó là 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)
    }
}

Đối với Tài liệu, hãy tham khảo SQLiteDatabase.setForeignKeyConstraintsEnabled


3
Tài liệu bạn đã đăng cho thấy: A good time to call this method is right after calling openOrCreateDatabase(File, SQLiteDatabase.CursorFactory) or in the onConfigure(SQLiteDatabase) callback. Vì vậy, thay vì onOpen, onConfigurecó vẻ là nơi thích hợp.
Paul Woitaschek

4

Tôi không nghĩ SQLite hỗ trợ điều này ra khỏi hộp. Những gì tôi đang làm trong ứng dụng của mình là:

  1. Tạo giao dịch
  2. Xóa dữ liệu chi tiết (điểm tham chiếu trong ví dụ của bạn)
  3. Xóa dữ liệu chính (các tuyến đường trong ví dụ của bạn)
  4. Cam kết giao dịch thành công

Bằng cách đó, tôi chắc chắn rằng tất cả dữ liệu đều bị xóa hoặc không có.


Nhưng bạn có đang xóa khỏi cả hai bảng bằng một phương pháp không?
jcrowson

Có, tôi đã xem xét khá nhiều mẫu Ghi chú từ API. Khi tôi xóa những gì sẽ là một tuyến đường trong trường hợp của bạn, tôi sẽ tạo giao dịch, xóa đường đi và điểm tham chiếu và thực hiện giao dịch. Đó là tất cả trong một lần.
Thorsten Dittmar

4

Trình kích hoạt được hỗ trợ bởi android và kiểu xóa theo tầng đó không được sqlite hỗ trợ. Có thể tìm thấy một ví dụ về việc sử dụng trình kích hoạt trên Android tại đây . Mặc dù sử dụng các giao dịch như Thorsten đã nêu có lẽ cũng dễ dàng như một trình kích hoạt.


3

Phiên bản SQLite trong android 1.6 là 3.5.9 nên không hỗ trợ khóa ngoại ...

http://www.sqlite.org/foreignkeys.html "Tài liệu này mô tả hỗ trợ cho các ràng buộc khóa ngoại SQL được giới thiệu trong SQLite phiên bản 3.6.19."

Trong Froyo, đó là phiên bản SQLite 3.6.22, vì vậy ...

CHỈNH SỬA: để xem phiên bản sqlite: adb shell sqlite3 -version


Vậy có cách nào để buộc những ràng buộc đó không .. Ý tôi là có cách nào để nâng cấp phiên bản sqlite .. bởi vì chúng tôi phải hỗ trợ phiên bản phần mềm lên android 2.1 có phiên bản sqlite 3.5.9 như trên
NullPointerException

Không, bạn phải tự mình xử lý mọi thứ :(
GBouerat,

1

Các khóa ngoại có "on delete cascade" được hỗ trợ trong SQLite trong Android 2.2 trở lên. Nhưng hãy cẩn thận khi sử dụng chúng: đôi khi lỗi được báo cáo khi kích hoạt một khóa ngoại trên một cột, nhưng vấn đề thực sự nằm ở ràng buộc khóa ngoại của cột khác trong bảng con hoặc một số bảng khác tham chiếu đến bảng này.

Có vẻ như SQLite kiểm tra tất cả các ràng buộc khi kích hoạt một trong số chúng. Nó thực sự được đề cập trong tài liệu. Kiểm tra ràng buộc DDL so với DML.


0

Nếu bạn đang sử dụng Android Room, hãy làm như hình bên dưới.

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()
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.