T-file

一歩踏み出す勇気を全力で応援するブログ

【PHP・Symfony + EC-CUBE】テーブル作成時の外部キー制約違反の解決

こんにちは、webエンジニア歴4年のtakaです。

今回は、EC-CUBEでテーブル作成時に外部キー制約違反のエラーが出ました。
EC-CUBEの例で話を進めますが、Laravelなど別のフレームワークでもこちらの記事を参考に解決できると思いますので、ご覧ください。

では、いきましょう。

前提・実現したいこと

既にbooksテーブルが存在しています。

booksテーブルに新しくカテゴリーのカラムを追加したい。

行いたい動作

  1. book_categoriesテーブルを新しく追加する
  2. book_categoriesテーブルには2レコードしか想定していないので、2レコードデータを挿入する
  3. booksテーブルにbook_category_idカラムを追加する
  4. 外部キー制約を設ける

マイグレーションファイルを作成し、1~4の処理を行う記載を記載していきました。

該当のソースコード

作成したマイグレーションファイルがこちらです。

<?php

namespace DoctrineMigrations;

use Doctrine\DBAL\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema;


/**
 * Auto-generated Migration: Please modify to your needs!
 */
 class Version20210101000000 extends AbstractMigration
 {
  /**
  * @param Schema $schema
  */
  public function up(Schema $schema)
  {
    // this up() migration is auto-generated, please modify it to your needs
    $this->addSql("CREATE TABLE book_categories (id SMALLINT NOT NULL, name LONGTEXT NOT NULL, rank SMALLINT NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE = InnoDB ;");  // book_categoriesテーブルの作成
    $this->addSql("INSERT INTO book_categories (id, name, rank) VALUES (1, '図鑑', 1);"); // book_categoriesテーブルにデータ挿入
    $this->addSql("INSERT INTO book_categories (id, name, rank) VALUES (2, '雑誌', 2);"); // book_categoriesテーブルにデータ挿入

    $this->addSql("ALTER TABLE books ADD book_category_id SMALLINT NOT NULL ;"); // booksテーブルにbook_category_idカラムを追加
    $this->addSql("ALTER TABLE books ADD CONSTRAINT FK_98604EA3AAAA0A00 FOREIGN KEY (book_category_id) REFERENCES mtb_lending_content (id);"); // 外部キー制約の使用
    $this->addSql("CREATE INDEX IDX_98604EA3AAAA0A00 ON books (book_category_id);"); // インデックスの作成
  }


 /**
  * @param Schema $schema
  */
  public function down(Schema $schema)
  {
    // this down() migration is auto-generated, please modify it to your needs

    $this->addSql("ALTER TABLE books DROP FOREIGN KEY `FK_98604EA3AAAA0A00`;");
    $this->addSql("ALTER TABLE books DROP COLUMN book_category_id;");
    $this->addSql("DROP TABLE IF EXISTS `book_categories`;");
  }
 }

発生している問題・エラーメッセージ

マイグレーションファイルを作成したので、マイグレーションの実行を行ったところ下記のエラーが出力されました。

$ app/console migrations:migrate

[Doctrine\DBAL\Driver\PDOException]                                                                                                                                          
  SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails

解決方法

必要な方はロールバックを駆使しマイグレーションを行う前の状態にまず戻ります。

book_categoriesテーブルの作成

この3行でbook_categoriesテーブルが生成されます。

    $this->addSql("CREATE TABLE book_categories (id SMALLINT NOT NULL, name LONGTEXT NOT NULL, rank SMALLINT NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE = InnoDB ;");  // book_categoriesテーブルの作成
    $this->addSql("INSERT INTO book_categories (id, name, rank) VALUES (1, '図鑑', 1);"); // book_categoriesテーブルにデータ挿入
    $this->addSql("INSERT INTO book_categories (id, name, rank) VALUES (2, '雑誌', 2);"); // book_categoriesテーブルにデータ挿入

できたテーブルがこちらです。

book_categoriesテーブル

id name rank
1 図鑑 1
2 雑誌 2

booksテーブルにbook_category_idカラムを追加

こちらの1行でbook_category_idカラムを追加します。

    $this->addSql("ALTER TABLE books ADD book_category_id SMALLINT NOT NULL ;"); // booksテーブルにbook_category_idカラムを追加

できたテーブルがこちら。

booksテーブル
id name ・・・ book_category_id
1 aaa ・・・ 0
2 bbb ・・・ 0
3 ccc ・・・ 0
・・・

はい、book_category_idの値が「0」でbook_categoriesテーブルにidが0のレコードがなかったのですね。
なのでbook_category_idにdefaultで1を入れるように設定します。

    $this->addSql("ALTER TABLE books ADD book_category_id SMALLINT DEFAULT 1 NOT NULL ;"); // DEFAULT 1 を追加

再度マイグレーションを試す

再度マイグレーションを行なってみます。

$ app/console migrations:migrate
$ 

うまく実行できました。

まとめ

いかがでしたか?

マイグレーションファイルの書き方が悪いのかなと30分くらい考えていました。
後から見ると簡単なことでしたね。

この記事を見て解決できた方が居れば幸いです。