Не удается удалить столбец sqlite при обновлении модели laravel / eloquent с помощью сценария миграции менеджера баз данных - PullRequest
0 голосов
/ 14 октября 2019

У меня проблема с попыткой запустить тесты в моем приложении Laravel. У меня есть структура таблицы следующим образом:

Эти запросы SQL были сгенерированы сценарием экспорта с использованием TablePlus, так как я подумал, что это был самый простой способ поделиться структурой таблицы.

После миграции * СЕЙЧАС

CREATE TABLE `business_system_role_location_type` (
  `business_system_role_id` char(36) COLLATE utf8mb4_unicode_ci NOT NULL,
  `location_type_id` char(36) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`business_system_role_id`,`location_type_id`),
  KEY `business_system_role_loc_type_fk` (`location_type_id`),
  CONSTRAINT `business_system_role_loc_type_fk` FOREIGN KEY (`location_type_id`) REFERENCES `location_types` (`id`),
  CONSTRAINT `business_system_role_loc_type_role_id_fk` FOREIGN KEY (`business_system_role_id`) REFERENCES `business_system_roles` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

До миграции

CREATE TABLE `business_system_role_location_type` (
  `business_system_role_id` char(36) COLLATE utf8mb4_unicode_ci NOT NULL,
  `location_type` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`business_system_role_id`,`location_type`),
  CONSTRAINT `business_system_role_loc_type_role_id_fk` FOREIGN KEY (`business_system_role_id`) REFERENCES `business_system_roles` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Итак, как вы видите, я запустил миграцию и удалил location_type и заменили его внешним ключом для новой таблицы location_types. И business_system_role_id, и location_type установлены на УНИКАЛЬНЫЙ ПЕРВИЧНЫЙ КЛЮЧ.

Это все работает нормально с MySQL, но как только я пытаюсь запустить любой из моих тестов (с использованием SQLite), он перестает работать и жалуется: Illuminate\Database\QueryException : SQLSTATE[23000]: Integrity constraint violation: 19 NOT NULL constraint failed: business_system_role_location_type.location_type (SQL: insert into "business_system_role_location_type" ("business_system_role_id", "location_type_id") values (bb2051c2-1b5c-498d-bbcf-6dd9e20c4803, 38215722-bcba-4cac-8c83-fe867d8d8e65))


Вопрос

Почему я получаю ограничение NOT NULL для business_system_role_location_type.location_type, когда этот столбец больше не существует? Я пробовал установить location_type в nullable->(true) перед миграцией, предполагая, что он может обновить некоторые настройки SQLite, но это не сработало.

Я пытался настроить свой код так, чтобы он выполнял $model->location_type = 'something' до$model->save(), и это сработало ... Хотя столбец не существует. Все ссылки на него были удалены. Я не хочу жить здесь с обходным путем и хотел бы выяснить причину этой ошибки.

Модель выглядит следующим образом:

class BusinessSystemRoleLocationType extends Model
{
    protected $table = 'business_system_role_location_type';

    protected $fillable = [
        'business_system_role_id',
        'location_type_id',
    ];

    public $incrementing = false;

    public $timestamps = false;

    public function businessSystemRole(): BelongsTo
    {
        return $this->belongsTo(
            BusinessSystemRole::class,
            'business_system_role_id',
            'id'
        );
    }
}

Любая помощь здесь будет принята с благодарностью. :)


Редактировать - Миграция

Вот часть миграции, которая имеет дело с этой таблицей:

        // Add location_type_id field to table
        Schema::table('business_system_role_location_type', function (Blueprint $table) {
            // Must be nullable until it is populated with data
            $table->uuid('location_type_id')
                ->nullable()
                ->after('business_system_role_id');
        });

        // Assign location_type_id value to all entries
        BusinessSystemRoleLocationType::all()->each(function ($businessSystemRoleLocationType) {
            $locationTypeDataSetIndex = \array_search(
                $businessSystemRoleLocationType->location_type,
                \array_column($this->locationTypeDataSet, 'existsAs'),
                true
            );
            if ($locationTypeDataSetIndex !== false) {
                $newLocationTypeData = $this->locationTypeDataSet[$locationTypeDataSetIndex];
                $newLocationType = LocationType::whereSlug($newLocationTypeData['slug'])->get()->first();
            } else {
                $newLocationType = LocationType::all()->first();
            }
            $businessSystemRoleLocationType->location_type_id = $newLocationType->id;
            $businessSystemRoleLocationType->save();
        });

        // Adjust primary index and add foreign keys, and drop location_type field from table
        Schema::table('business_system_role_location_type', function (Blueprint $table) {
            $table->dropForeign('business_system_role_loc_type_role_id_fk');
            $table->dropPrimary(['business_system_role_id', 'location_type']);
        });
        Schema::table('business_system_role_location_type', function (Blueprint $table) {
            // ATTEMPT TO SET FIELD TO NULLABLE BEFORE REMOVING IT, MAYBE THIS WILL FIX THE NOT NULL CONSTRAINT ERROR?
            $table->string('location_type')->nullable()->change();
        });
        Schema::table('business_system_role_location_type', function (Blueprint $table) {
            $table->foreign('location_type_id', 'business_system_role_loc_type_fk')
                ->references('id')
                ->on('location_types');
            $table->foreign('business_system_role_id', 'business_system_role_loc_type_role_id_fk')
                ->references('id')
                ->on('business_system_roles')
                ->onDelete('cascade');

            // Now set not nullable UUID (Doctrine (change()) does not support UUID type)
            $table->string('location_type_id', 36)->change();

            $table->primary(['business_system_role_id', 'location_type_id'], 'business_system_role_loc_type_pk');

            $table->dropColumn('location_type');
        });

Редактировать 2 - Решение

Я редактирую здесь, чтобы предоставить свое решение - хотя я оставлю это открытым, так как другие, скорее всего, дадут лучший ответ.

Из чегоЯ могу понять, чтобы удалить ограничения в базе данных SQLite, рекомендуется удалить таблицу и воссоздать ее. (См. Здесь: https://stackoverflow.com/a/4007086/9675332). Похоже, что SQLite сохраняет эти ограничения где-то и не удаляет их на самом деле только потому, что вы удалили столбец. Я действительно не хотел идти по этому пути, поэтому вот что я сделал:

Решение 1: Я изменил свою миграцию, чтобы задать для поля значение по умолчанию перед его удалением, и это действительно прошло тест (хотя впоследствии он не прошел ограничение UNIQUE, так чтов моем случае это не рабочее решение, но вполне может работать для других!)

Решение 2: Вероятно, то, что я должен был сделать для начала. Я просто переименовал столбец из location_type до location_type_id и вручную установите его на char(36). Похоже, что он обновил все в фоновом режиме вместе с ним и теперь проходит тесты.

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