我正在制作一个记事应用,每个记事都有一个标签。有两个表,一个表用于Notes,一个表用于Labels。当前,我正在使用ForeignKey.CASCADE
,如果用户删除标签,则带有该标签的注释将被删除。我想要一个默认值,以便在删除标签时,注释将其作为新标签,并且不会被删除。
我认为解决方案是使用onDelete = ForeignKey.SET_DEFAULT
,但我不知道如何以及在何处使用它。
笔记类别:
@Entity(tableName = "tbl_notes",
foreignKeys = @ForeignKey(entity = Label.class,
parentColumns = "label_id",
childColumns = "note_label_id",
onDelete = ForeignKey.CASCADE))
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")
private int noteLabel;
标签类别:
@Entity(tableName = "tbl_label")
public class Label {
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "label_id")
private int id;
@ColumnInfo(name = "label_name")
private String labelName;
答案 0 :(得分:2)
您可以从enter link description here查看文档。
他们说:
“ SET DEFAULT”操作类似于SET_NULL,不同之处在于,每个子键列均设置为包含列的默认值而不是NULL。
因此您必须输入默认值。像这样
@ColumnInfo(name = "c_id", defaultValue = "1")
private long id;
答案 1 :(得分:1)
我刚刚阅读了内联文档,因为这是它所说的
“ SET DEFAULT”操作类似于SET_NULL,除了每个 子键列设置为包含列的默认值 而不是NULL。
这意味着您只需要定义它。它将设置Notes表中列的默认值。在为Note表设计架构时,必须确保将其与映射列的默认值链接。
答案 2 :(得分:1)
要设置外键的 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
中的内容,则以上内容将导致外键冲突。
例如,根据上述实体和合适的Dao(带有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个音符。删除ID为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之后,注1现在根据SET_DEFAULT操作引用了Label1而不是Label3。
但是尝试删除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)