やりたいこと
-
Company
とEmployee
のように親子関係にあるテーブルを作成 -
employee
テーブルにcompany_id
という外部キーを設定 - その後、
onDelete
onUpdate
に対する挙動を設定し忘れたことに気づいたので後から設定をしたい
マイグレーションファイル
- companies
class CreateCompanyTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('companies', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('company');
}
}
- employee
class CreateEmployeeTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('employee', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->nullable();
$table->integer('company_id')->unsigned();
$table->foreign('company_id')->references('id')->on('companies');
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('employee');
}
}
マイグレーションは問題なくて、その後も色々なテーブルを追加していった後、onDelete / onUpdate の設定ができていないことに気づいて、「全部ロールバックするのも気が重いし、一部分だけ弄れないかな…」と逡巡して以下の方法を取った。
やったこと
あまりお行儀がよくないかもしれないが、 employee
テーブルのcompany_id
だけを drop するマイグレーションファイルを作り、php artisan migrate
を実行。
その後外部キー制約を再設定するマイグレーションファイルを作って、同様にphp artisan migrate
。
- 外部キーを一旦Drop
class DropForeignKeyFromEmployee extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
//外部キー制約を引き剥がす時は dropForeign('テーブル名'_'外部キー名'_foreign);
Schema::table('employee', function (Blueprint $table) {
$table->dropForeign('employee_company_id_foreign');
});
}
}
public function up()
{
//子テーブルに対象レコードがある場合、親テーブルのレコード削除を禁止 ->onDelete('restrict');
//親テーブルのレコード更新は許可 ->onUpdate('cascade');
Schema::table('employee', function (Blueprint $table) {
$table->index('company_id');
$table->foreign('company_id')->references('id')->on('companies')
->onDelete('restrict')
->onUpdate('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('employee', function (Blueprint $table) {
$table->dropForeign('employee_company_id_foreign');
});
}
問題点
このやり方だとロールバックした時にDropForeignKeyFromEmployee
エラーで怒られる。なので、最初からなるべくテーブル作成時に onDelete / onUpdate の条件は慎重に考えて設定した方がいい。うまく後付けで設定できる方法があればコメントで教えていただきたいです。個人的に思いつくのがMySQLのコマンドで直接テーブルを書き換える手段だけなので…
その他ハマったこと
onDelete('restrict')
を設定したあと、Laravel アプリケーションからCompany::destroy
で実際に削除を試してみたところ、なんと制約に引っかからず普通に削除できてしまった…
どうやらuse SoftDelete
で論理削除をさせている場合、物理削除と違ってdeleted_at
にタイムスタンプを書き込むだけなので制約をすり抜けてしまうらしい…。早めに知っておきたかった。
参考リンク
What if onDelete is restrict instead of cascade?
[マイグレーションまとめ(Laravel5)]
(https://qiita.com/hththt/items/ae871f59b337f209d1ad)