如何在会议室数据库中使用ForeignKey.SET_DEFAULT?

时间:2019-10-15 13:14:30

标签: android android-room

我正在制作一个记事应用,每个记事都有一个标签。有两个表,一个表用于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;

3 个答案:

答案 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)