BLOGカルテットコミュニケーションズ開発部ブログこの記事は公開されてから1年以上経過しています。情報が古い可能性がありますのでご注意ください。はじめにDoctrineは多機能で私も開発においてはたいへん便利に使っています。反面、多機能がゆえにどの機能が何を提供してくれるのか把握できていないために苦労することもしばしばです。ここでは私がいつもどれがなにを示すのかわからなくて毎回ドキュメントを見ながら使っていたcascade={"remove"}、onDelete="CASCADE"、orphanRemoval=trueの記述がもたらす各振舞についてこの場を借りて整理してみたいと思います。データ削除$em->remove($user);$em->flush();これ以降、エンティティの定義方法を変更することでテストスクリプトの振舞にどう影響するのかを確認してみます。プレーンな状態まずは考えうるもっともプレーンな状態でエンティティを定義してみます。//...}エンティティ定義をもとにスキーマを作成後、テストスクリプトを実行するとエラーが送出され、完遂しません。/path/to/2016-12-doctrine/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php:91実行時に走ったクエリは以下です。1;テストスクリプトのコードではUserエンティティだけを削除しようとしています。DBにおいてはProfile.user_idからUser.idに外部キーが貼られているため、紐付いた親にあたるUserエンティティが存在しなくなる矛盾からエラーになっていますね。cascade={“remove”}そこでcascade={"remove"}を追記してみます。$user;}スキーマを更新後テストスクリプトを実行してみます。エラーになることなく完遂しました。ちなみに走ったクエリは以下です。1;はさきほどは見られなかったクエリですね。1;これはテストスクリプトが以下のように書き換えられたのと同様の動きといえます。$em->remove($profile);$em->remove($user);$em->flush();つまりcascade={"remove"}におけるremoveはEntityManagerに生えているremoveメソッドを指す識別子だったことがわかります。remove以外にもpersistやmergeなどが定義できますし複数の定義も可能です。onDelete=”CASCADE”removeとdeleteは同義ですしcascadeという文言もありますし、cascade={"remove"}とやりたいことは似ているように感じます。実際に動きを見てみましょう。$user;}上記のように書き換えた後、ここではひとまずスキーマの更新を行わずテストスクリプトを実行してみます。さきほどと同じように外部キーエラーが送出され完遂しません。/path/to/2016-12-doctrine/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php:91ちなみに走ったクエリは以下です。プレーンな状態のときと同様ですね。onDelete="CASCADE"は何もしてくれないのでしょうか?そんなはずはありません。以下のようにスキーマを更新してみます。CASCADE再度テストスクリプトを実行すると無事に完遂しました。ちなみに走ったクエリは以下です。エラーになったさきほどと変わりありません。1;つまりonDelete="CASCADE"はDoctrineがORMとしてよしなに何かをしてくれるためではなく、DBのレイヤで対応するようにDDLを生成するための記述でしかないということですね。追記して使ってみます。$user;}スキーマを更新してからテストスクリプトを実行してみると以下のクエリが走り、所望の振舞となりました。1;cascade={"remove"}と同様の動きのように見えますね。どちらのように書いても同じなのでしょうか?cascade={“remove”}とorphanRemoval=trueの違いテストスクリプトの仕様を以下のコードのように「ユーザに新たなプロフィールをセットする」というように変更してみます。$em->persist($profile2);$em->flush();まずは以下のようにcascade={"remove"}を追記してみます。$user;}さっそくテストスクリプトを実行してみます。走ったクエリは以下です。DELETE文は発行されていませんのでこれは所望の振舞ではありません。(NULL)そこでorphanRemoval=trueに戻してみます。$user;}テストスクリプトを実行してみると以下のクエリが走ります。これで所望の振舞となりました。1;以上から、cascade={"remove"}が親が削除されることでそれに伴い子も削除されるのに対して、orphanRemoval=trueは親そのものが存在しても子との関係が断たれた状態になった時点で子が削除されるようですね。それぞれの記述のもたらす振舞をそれぞれ確認してみました。目的が同様に見えても状態によっては別の振舞を行うことが明確になりました。DBに近い振舞はパフォーマンスへの影響も小さくないこともあり手法の選定は慎重になりたいですね。TtskchTheme。