Перенос комнаты - как изменить onDelete ForeignKey? - PullRequest
0 голосов
/ 18 июня 2020

У меня есть @Entity в базе данных комнат. Он имеет 2 внешних ключа и выглядит так:

@Entity(
    tableName = "member_table",
    primaryKeys = ["member_chat_id", "member_user_id"],
    foreignKeys = [
        ForeignKey(
            entity = Chat::class,
            parentColumns = arrayOf("chat_id"),
            childColumns = arrayOf("member_chat_id"),
            onDelete = ForeignKey.NO_ACTION
        ),
        ForeignKey(
            entity = User::class,
            parentColumns = arrayOf("user_id"),
            childColumns = arrayOf("member_user_id"),
            onDelete = ForeignKey.NO_ACTION
        )
    ], indices = [
        Index(value = ["member_chat_id", "member_user_id"], unique = true)
    ]
)

Теперь мне нужно изменить первый внешний ключ на onDelete = ForeignKey.CASCADE, чтобы удалить эти объекты вместе с соответствующими Chat::class Как мне выполнить миграцию с onDelete = ForeignKey.NO_ACTION на onDelete = ForeignKey.CASCADE?

1 Ответ

0 голосов
/ 18 июня 2020

Документация SQLite для ALTER TABLE в разделе «Внесение других видов изменений схемы таблицы» объясняет, что единственные команды изменения схемы, напрямую поддерживаемые SQLite, - это «переименовать таблицу», «переименовать столбец. "и" добавить столбец ".

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

  1. Создать новую таблицу с желаемой схемой ("member_table_new")
  2. Скопировать данные из существующей таблицы ("member_table") в новая таблица
  3. Удалить существующую таблицу
  4. Переименовать новую таблицу, например, member_table_new в «member_table»

Пример этого (в Java) находится в Room Sample .

Для вашего изменения миграция выглядит примерно так. Если в member_table есть больше полей, добавьте их. Также не забудьте добавить миграцию в ваш оператор построения базы данных .

// TODO Change version numbers as needed
val MIGRATION_4_5 = object : Migration(4, 5) {
    override fun migrate(database: SupportSQLiteDatabase) {
        // Create the new table with "ON DELETE CASCADE" for member_chat_id foreign key action
        database.execSQL("""
            CREATE TABLE `member_table_new` (
            `member_chat_id` INTEGER NOT NULL,
            `member_user_id` INTEGER NOT NULL,
            PRIMARY KEY(`member_chat_id`, `member_user_id`),
            FOREIGN KEY(`member_chat_id`) REFERENCES `Chat`(`chat_id`) ON UPDATE NO ACTION ON DELETE CASCADE,
            FOREIGN KEY(`member_user_id`) REFERENCES `User`(`user_id`) ON UPDATE NO ACTION ON DELETE NO ACTION )"""
            .trimIndent())

        // Copy the rows from existing table to new table
        database.execSQL("""
            INSERT INTO member_table_new (member_chat_id, member_user_id)
            SELECT member_chat_id, member_user_id FROM member_table"""
            .trimIndent())

        // Remove the old table
        database.execSQL("DROP TABLE member_table");
        // Change the new table name to the correct one
        database.execSQL("ALTER TABLE member_table_new RENAME TO member_table");

    }
}

В документации SQLite говорится, что эти операции должны выполняться в транзакции. Room выполняет миграции в транзакции, поэтому вам не нужно добавлять свои собственные.

При составлении оператора SQL для создания новой таблицы полезно иметь схему Room для таблицы. Если вы еще этого не сделали, включите экспорт информации схемы в файл JSON.

...