質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

Q&A

解決済

1回答

4196閲覧

外部キー制約のCASCADE指定における子テーブルのレコード自動削除について

yuki84web

総合スコア1857

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

0グッド

0クリップ

投稿2020/06/26 05:05

実現したいこと

親テーブルのレコードを削除した際に、紐づく子テーブルのレコードも自動削除したい。

該当のソースコード

Post Model(親)

php

1class CreatePostsTable extends Migration 2{ 3 public function up() 4 { 5 Schema::create('Posts', function (Blueprint $table) { 6 $table->bigIncrements('id'); 7 $table->string('name'); 8 $table->timestamps(); 9 $table->softDeletes(); 10 } 11 } 12}

php

1class Post extends Model 2{ 3 use SoftDeletes; // 論理削除 4 5 public function users() 6 { 7 return $this->hasMany('App\User'); 8 } 9}

User Model(子)

php

1class CreateUsersTable extends Migration 2{ 3 public function up() 4 { 5 Schema::create('users', function (Blueprint $table) { 6 $table->bigIncrements('id'); 7 $table->unsignedBigInteger('post_id'); 8 $table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade'); 9 $table->string('name'); 10 $table->timestamps(); 11 } 12 } 13}

php

1class User extends Model 2{ 3 // 物理削除 4 5 public function post() 6 { 7 return $this->belongsTo('App\Post'); 8 } 9}

レコード削除処理

php

1class PostController extends Controller 2{ 3 public function destroy(Post $post) 4 { 5 $post->delete(); // 親テーブルの指定レコードの削除 6 } 7}

発生した問題

削除対象の親テーブルのレコードに紐づく子テーブルのレコードは物理削除されない

試したこと

Post Model(親)

php

1class Post extends Model 2{ 3 use SoftDeletes; // 論理削除 4 5 public function users() 6 { 7 return $this->hasMany('App\User'); 8 } 9 10 /* 下記を追加 */ 11 protected static function boot() 12 { 13 parent::boot(); 14 self::deleting(function ($post) { 15 $post->users()->delete(); 16 }); 17 } 18}

上記により削除されるようになりましたが、
「外部キー制約の設定さえすれば親テーブルの削除処理実行のみで紐づく子テーブルのレコードも自動削除される」と思っておりました。
私の認識が間違っていますでしょうか?

補足情報

Laravel 6.8

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

migrationファイルのOnDleteの記述は、
laravelのModelがそれによって処理をうまいことやってくれる・・・とかいうヤツではなくて、
DBのテーブル定義の設定ですよね。

これはつまり、

DBのテーブルから実際にはデータが消えるわけではない「親の論理削除」によって、
外部キーを持つ子が自動的に物理削除されることはない

ということになります。

なので、仮に子テーブルの設定を

//子がいたら、親は削除できない設定 $table->foreign('post_id')->references('id')->on('posts')->onDelete('restrict');

にしても、親の論理削除でエラーが発生することはないようです。


もしかしたら、語弊があるかもしれないので、補足を。。

単なる定義であって、削除処理は書く必要

は、今回のケースが
「親の論理削除」で、「子の物理削除」をしたい話なので、そうなります。

先にも説明しましたが、migrationファイルの設定で自動的に削除実行するのは「DB」なので、
【DBにとっての削除】=データの有無が変化する「親の物理削除」が、子テーブルへ処理のきっかけとして必要になるのです。
論理削除は、データを残したまま無効にする。。という【プログラム上の仕様】なので、【DBにとっての削除】には該当しません。

つまり、今のままの設定でも、親を「完全削除(強制物理削除)$post->forceDelete(); 」すれば、子の削除処理を書かずともDBが自動的に子も削除してくれます。

なお、DBによっては、親の論理削除を条件に子の削除を実行するtriggerを付けるようなことも可能ではありますが、migrationファイルで簡単に定義は出来ないかも?(やったことないのでもしかしたら簡単かもしれませんが・・)

私の個人的な意見としては、migrationで複雑な設定をするよりも、コードで書いた方が簡単で早いかなぁと思ったりもします。。。

投稿2020/06/26 07:47

編集2020/06/29 00:06
mix-peach

総合スコア1910

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yuki84web

2020/06/26 08:43

なるほど、単なる定義であって、削除処理は書く必要があるのですね。ありがとうございました。
yuki84web

2020/06/29 04:06

補足ありがとうございます。論理削除はデータベースからすれば"更新"なので、書く必要があったのですね。仰る通り、マイグレーションは簡潔にして、モデルやコントローラに書くのが個人的にも分かりやすくて良いのかなと思いました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問