База данных комнаты: ограничение NOT NULL при удалении не выполнено - PullRequest
1 голос
/ 24 сентября 2019

У меня есть следующие объекты: Session и Label:

@Entity(
    foreignKeys =
    @ForeignKey(
            entity = Label.class,
            parentColumns = {"id", "archived"},
            childColumns = {"labelId", "archived"},
            onUpdate = CASCADE,
            onDelete = SET_DEFAULT))
    public class Session {

    @PrimaryKey(autoGenerate = true)
    public long id;

    @Nullable
    public String label = null;

    public boolean archived = false;
}

@Entity(primaryKeys = {"id", "archived"})
public class Label {

    @NonNull
    public String id;

    public boolean archived = false;
}

При удалении Label, прикрепленного к Session, я получаю NOT NULL constraint failed для Session.archived.

Что я здесь не так делаю?

1 Ответ

1 голос
/ 24 сентября 2019

Я считаю, что проблема заключается в использовании типа логический , как в public boolean archived = false;.

Поскольку логический является основным типом Java, тогда он имеетнеявное @ NonNull (таблица создается с ограничением NOT NULL)

С помощью Room вы не можете (я верю) установить значения по умолчанию, которые генерируются в таблице SQLite, поэтому при использовании onDelete SET_DEFAULTзначение по умолчанию будет NULL , поскольку фактическое значение по умолчанию не задано.

  • использование = false не влияет на фактическую таблицу SQLite, то есть на определение столбца, если используется Boolean , будет labelId INTEGER, а не labelId INTEGER DEFAULT 0.

Если предположить, что NULL является приемлемым, тогда вы можете использовать Boolean (Объект) вместо логического (основной тип).Объекты могут быть нулевыми.

т.е. в Сеанс использовать

public Boolean archived = false;

Визуальное объяснение: -

Ниже приведен код, сгенерированный Room,для Session Entity, но с добавленным дополнительным столбцом, используя: -

.........
public boolean archived = false;
public Boolean other_archived = false; //<<<<<<<<<< ADDED
........

Код, сгенерированный комнатой: -

CREATE TABLE IF NOT EXISTS `Session` (
    `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 
    `label` TEXT, 

    `archived` INTEGER NOT NULL, /*<<<<<<<<<< boolean so NOT NULL */ 
    `other_archived` INTEGER, /*<<<<<<<<<< Boolean so no NOT NULL */
    FOREIGN KEY(`label`, `archived`) REFERENCES `Label`(`id`, `archived`) ON UPDATE CASCADE ON DELETE SET DEFAULT)

Extra

Если вы хотитедля архивированного столбца в таблице сеансов должно быть 0 (false), тогда вам придется изменить таблицу.Это повлечет за собой

  1. Создание таблицы замены, которая является такой же, за исключением того, что определение столбца метки будет label INTEGER DEFAULT 0 (т. Е. Добавлено DEFAULT 0)
  2. Копирование данных из сеансатаблицу в таблицу замены, например, INSERT INTO replacement_Session SELECT * FROM Session;
  3. Переименование таблицы сеанса.
  4. Переименование таблицы замены в сеанс.
  5. В случае успеха Удалите переименованную таблицу сеанса.

В качестве альтернативы (я думаю) вы можете использовать AFTER UPDATE TRIGGER, чтобы изменить значение NULL на 0 (false).

Любой из этих вариантов необходимо будет выполнить за пределами Room или до того, как RoomDatabase будетвстроенный.

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