CakePHPでデータ削除

            <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の成功・失敗を取得することはできなかった。

残念だな。