<div class="section">
この記事はCakePHP1.2向けです。
CakePHPでテーブルから1行削除するときには、del()を使います。
$r1 = $this->Model->del($id); //$id => 行のid
もしくは、DELETE文を書いて、query()かexecute()を使う。
$sql = 'DELETE FROM model WHERE id = 10'; $r2 = $this->Model->execute($sql);
では、上記の2つの方法の違いはなんだろうか?
それをまとめておく。
1. 戻り値
上の例で、$r1と$r2の関係性を整理しておこう。
関数 | delete | 成功 | 失敗 |
del | r1 | true | false |
execute | r2 | array() | array() |
executeではDELETEが成功したのか、失敗したのかを判定する方法がない。
これでは、トランザクション処理中に「もしDELETEが失敗したときにロールバックする」みたいな処理ができない。
これを解決する方法は調べたが、よくわからないので、ロールバックしなければいけないようなときは、del()を使いたいです。
問題 => execute()だと、成功と失敗をうけとることができない。
2. SQL
SQLにも違いがある。
execute()はもちろん、書いたSQLが実行される。
del()では、cakePHPがDELETE文を生成してくれるわけだが、
モデル内でbelongsToやhasOneなどでアソシエーションを指定していると、
アソシエーションしているテーブルをJOINしてしまうようです。
DELETE FROM model AS Model LEFT JOIN model2 AS Model2 Model.model2_id = Model2.id WHERE Model.id = 10;
こんなJOINは必要がないわけです。
JOINを回避する方法を調べたが、解決方法がよくわからず、unbindModel()や「$this->Model->recursive = -1」も試したが、JOINはされてしまうようです。
パフォーマンスを重視するなら、execute()を使ってもいいかと思います。
問題 => del()だと、必要ないテーブルがJOINされてしまう。
使い分けが上手くできればいいのかもしれないが、やっぱり気持ち悪いです。
1と2の解決策はあるのでしょうか?!
追記
1について。
execute()後に、findById()などで削除したデータがあるかどうかを調べれば、execute()が成功したのか?失敗したのか?わかるのではないかと思い、試してみた。
//削除するデータID $id = 125; //トランザクション $this->UserUsingAccessory->begin(); echo "トランザクション<br />"; //executeする前 $sql = sprintf('SELECT id FROM user_using_accessories WHERE id = %d', $id); $r = $this->UserUsingAccessory->query($sql); echo 'executeする前にSELECTでデータを取得した結果 => ' . var_dump($r) . '<br />'; //executeパターン $sql = sprintf('DELETE FROM user_using_accessories WHERE id = %d', $id); $r = $this->UserUsingAccessory->query($sql); echo 'executeの結果 => ' . var_dump($r) . '<br />'; //executeした後 $sql = sprintf('SELECT id FROM user_using_accessories WHERE id = %d', $id); $r = $this->UserUsingAccessory->query($sql); echo 'executeした後にSELECTでデータを取得した結果 => ' . var_dump($r) . '<br />'; //結果判定 if ($r) { $this->UserUsingAccessory->rollback(); echo "executeパターンでロールバック<br />"; return; } //コミット $this->UserUsingAccessory->commit(); echo "コミット<br />";
トランザクション array 0 => array 'user_using_accessories' => array 'id' => string '125' (length=3) executeする前にSELECTでデータを取得した結果 => array empty executeの結果 => array 0 => array 'user_using_accessories' => array 'id' => string '125' (length=3) executeした後にSELECTでデータを取得した結果 => executeパターンでロールバック
commit()をしなければデータの削除は行われないので、findByIdしすると普通にデータを取得できた。
DELETEしたのにデータがあるということは、成功したのか?失敗したのか?わからないので、結局execute()ではSQLの成功・失敗を取得することはできなかった。
残念だな。