こんにちは、webエンジニア歴4年のtakaです。
今回は、EC-CUBEでテーブル作成時に外部キー制約違反のエラーが出ました。
EC-CUBEの例で話を進めますが、Laravelなど別のフレームワークでもこちらの記事を参考に解決できると思いますので、ご覧ください。
では、いきましょう。
目次
前提・実現したいこと
既にbooksテーブルが存在しています。
booksテーブルに新しくカテゴリーのカラムを追加したい。
行いたい動作
- book_categoriesテーブルを新しく追加する
- book_categoriesテーブルには2レコードしか想定していないので、2レコードデータを挿入する
- booksテーブルにbook_category_idカラムを追加する
- 外部キー制約を設ける
マイグレーションファイルを作成し、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分くらい考えていました。
後から見ると簡単なことでしたね。
この記事を見て解決できた方が居れば幸いです。