Как использовать ForeignKey.SET_DEFAULT в базе данных комнаты? - PullRequest
0 голосов
/ 15 октября 2019

Я делаю приложение для заметок, и у каждой заметки есть ярлык. Есть две таблицы, одна для заметок и одна для меток. В настоящее время я использую 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 ]

2 голосов
/ 15 октября 2019

Вы можете проверить документы с введите описание ссылки здесь .
Они сказали:

Действия "SET DEFAULT" аналогичны SET_NULL, за исключением того, что каждое изВ столбцах дочерних ключей задано значение по умолчанию для столбцов, а не NULL.

Поэтому необходимо указать значение по умолчанию. как это

 @ColumnInfo(name = "c_id", defaultValue = "1")
 private long id;
1 голос
/ 15 октября 2019

Чтобы установить действие 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)
1 голос
/ 15 октября 2019

Я только что прочитал встроенную документацию, потому что здесь говорится о

Действия «SET DEFAULT» аналогичны действиям SET_NULL, за исключением того, что каждый из столбцов дочерних ключей содержит столбцы. значение по умолчанию вместо NULL.

Это означает, что вам просто нужно определить его. Он установит значение по умолчанию для вашего столбца в таблице заметок. При разработке схемы для таблицы заметок вы должны обязательно связать ее со значением по умолчанию для сопоставляемого столбца.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...