Чтобы установить действие onDelete или onUpdate внешнего ключа, вы должны использовать комбинацию SET_DEFAULT в аннотации внешнего ключа вместе с установкой значения по умолчанию равнымиспользуется в соответствующем столбце @ ColumnInfo , чтобы указать значение по умолчанию для этого столбца.
например,
@Entity(tableName = "tbl_notes",
foreignKeys = @ForeignKey(entity = Label.class,
parentColumns = "label_id",
childColumns = "note_label_id",
onDelete = ForeignKey.SET_DEFAULT)) //<<<<<<<<<
public class Note {
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "note_id")
private int id;
@ColumnInfo(name = "archived")
private boolean isArchive;
@ColumnInfo(name = "note_text")
private String noteText;
@ColumnInfo(name = "note_date")
private String noteDate;
@ColumnInfo(name = "note_label_id", defaultValue = "1") //<<<<<<<<<<
private int noteLabel;
Внимание
Используемое значение, очевидно, должно быть значением, которое не приведет к конфликту, поэтому как минимум значение по умолчанию должно быть значением, которое существует в справочном столбце родительской таблицы.
например,
Если в приведенном выше DELETE FROM tbl_label WHERE label_id = 1
были выполнены, то приведенное выше может привести к конфликту внешнего ключа.
Например, рассмотрим этот пример на основе вышеупомянутых сущностей и подходящих дао (с SET_DEFAULT): -
mNoteDao = mDatabase.noteDao();
mNoteDao.insertLabels(
new Label("Label1"),
new Label("Label2"),
new Label("Label3")
);
mNoteDao.insertNotes(
new Note(false,"Note1 uses lable 3","2019-01-01",3),
new Note(false,"Note2 uses label 2","2019-01-01",2),
new Note(false,"Note3 uses label 1","2019-01-01",1)
);
logAllNoteInfo("After populate\n\t");
mNoteDao.deleteLabelById(3);
logAllNoteInfo("After delete label 3\n\t");
mNoteDao.deleteLabelById(1);
logAllNoteInfo("After delete label 1\n\t");
Это добавляет 3 ярлыка и 3 примечания, каждое из которых использует один из ярлыков. Метка с идентификатором 3 удаляется, затем метка (метка по умолчанию) удаляется.
Результирующий вывод начинается с: -
2019-10-16 08:02:49.795 5914-5914/? D/NOTEANDLABEL: After populate
Note ID is 1 Text is Note1 uses lable 3 Label is Label3
2019-10-16 08:02:49.795 5914-5914/? D/NOTEANDLABEL: After populate
Note ID is 2 Text is Note2 uses label 2 Label is Label2
2019-10-16 08:02:49.796 5914-5914/? D/NOTEANDLABEL: After populate
Note ID is 3 Text is Note3 uses label 1 Label is Label1
2019-10-16 08:02:49.804 5914-5914/? D/NOTEANDLABEL: After delete label 3Note ID is 1 Text is Note1 uses lable 3 Label is Label1
2019-10-16 08:02:49.805 5914-5914/? D/NOTEANDLABEL: After delete label 3Note ID is 2 Text is Note2 uses label 2 Label is Label2
2019-10-16 08:02:49.806 5914-5914/? D/NOTEANDLABEL: After delete label 3Note ID is 3 Text is Note3 uses label 1 Label is Label1
Таблицы заполняются, как ожидается, ипосле удаления Label3 Note 1 теперь ссылается на Label1 вместо Label3 согласно действию SET_DEFAULT.
НО попытка удалить Lable1 приводит к исключению согласно: -
2019-10-16 08:02:49.808 5914-5914/? D/AndroidRuntime: Shutting down VM
--------- beginning of crash
2019-10-16 08:02:49.809 5914-5914/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: arm.androidroommigrations, PID: 5914
java.lang.RuntimeException: Unable to start activity ComponentInfo{arm.androidroommigrations/arm.androidroommigrations.MainActivity}: android.database.sqlite.SQLiteConstraintException: FOREIGN KEY constraint failed (code 787 SQLITE_CONSTRAINT_FOREIGNKEY)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3270)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: android.database.sqlite.SQLiteConstraintException: FOREIGN KEY constraint failed (code 787 SQLITE_CONSTRAINT_FOREIGNKEY)
at android.database.sqlite.SQLiteConnection.nativeExecuteForChangedRowCount(Native Method)
at android.database.sqlite.SQLiteConnection.executeForChangedRowCount(SQLiteConnection.java:831)
at android.database.sqlite.SQLiteSession.executeForChangedRowCount(SQLiteSession.java:756)
at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:66)
at androidx.sqlite.db.framework.FrameworkSQLiteStatement.executeUpdateDelete(FrameworkSQLiteStatement.java:46)
at arm.androidroommigrations.NoteDao_Impl.deleteLabelById(NoteDao_Impl.java:181)
at arm.androidroommigrations.MainActivity.onCreate(MainActivity.java:64)