#はじめに
Laravel5.7のEloquentを使ってDB(MySQL)の更新をするときに、複合キーが原因で詰まりまくったので解決法を書きます。
#何が起きた
弊プロジェクトではデータの更新の際は
// リクエストされたIDの行のインスタンスを取得
$table = TableA::where('ID', $request['id'])->lockForUpdate()->first();
// プロパティに値をセット
$table->NAME = 'taro';
$table->TEL = '00-0000-0000';
// 保存
$table->save();
上記のように、
- 1行に特定してインスタンスを取得
- プロパティに値をセット
-
save
メソッドで保存
という順序で保存するようにしています。
しかしこれが有効なのは主キーが1つの場合のみです。
TableA
がID
とDEMO_ID
からなる複合キーの場合・・・
// リクエストされたIDとDEMO_IDの行のインスタンスを取得
$table = TableA::where('ID', $request['id'])
->where('DEMO_ID', $request['demo_id'])
->lockForUpdate()
->first();
///// 以下略/////
上記の方法で保存すると、モデルの$primaryKey
に設定したキーが優先されます。
どういうことかというと、$primaryKey = 'ID'
としていた場合は
「IDとDEMO_IDを指定してインスタンスを取得したにも関わらず、IDが一致する行を全て更新する」
処理が走ります。不思議なのは、$table
にはちゃんと指定した1行のみが取得されていることです。よくわからなくてつらいです。
#解決策
この問題を解決するには、インスタンスを一旦変数にセットするのではなく、
「where句で条件を指定してそのまま更新する」必要があります。
(...ググりまくった結果、トレイトなるものを使用して解決できるようですが、設定をいじくる勇気はないので保留です)
TableA::where('ID', $request['id'])
->where('DEMO_ID', $request['demo_id'])
->lockForUpdate()
->update([
'NAME' => 'taro',
'TEL' => '00-0000-0000',
]);
このようにwhere句で行を特定し、そのままupdate
メソッドで更新すればちゃんと1行のみ更新できます。
#まとめ
複合キーの一番手軽な解決策だと思います。
ちなみに…モデルの$primaryKey
にキーを配列でセットしてみたけどダメでした。