Laravel5.2のEloquentで結合したテーブルの値についてはまったのでメモ。
やりたかったこと
2つのテーブルを外部結合したを取得したい
テーブル
t_project
field | |
---|---|
id | PK |
name |
t_result
field | |
---|---|
id | PK |
user_id | FK(t_user.id) |
project_id | FK(t_project) |
amount |
実行したかったSQL
SELECT *
FROM t_project LEFT OUTER JOIN t_result ON t_project.id = t_result.project_id
AND t_result.user_id = ?
ORDER BY t_result.amount desc
(※user_id条件はprepareStatement)
後続処理で使いたいのはt_projectの情報。
試したこと
最初に書いてみたもの
$projects = TProject:::leftJoin('t_result', function ($join) use ( $userId) {
$join->on('t_project.id', '=', 't_result.project_id')
->where('t_result.user_id', '=', $userId);
})
->orderBy('t_result.amount', 'desc')->get();
問題
Eloquentのモデル、TProjectのコレクションとして結果が取得できるわけだが、コレクションをループした時に
t_project.idが取れるものと思っていたら
id が null
になっているものがある・・・???
わかったこと
デバッグしてわかったのが、
結合先のテーブルも同名のカラムとして取得できる
=
Eloquentモデルのattribute配列のキーが同じ
=
LEFT OUTER JOIN でレコードがない場合=nullで上書きされる
(つまりLEFT OUTER JOINでテーブルがあったらt_result.idで上書きされる)
模様。
最初、別名でPKにしていたのでそれが悪いのかと思い、全部idに変えたんですよねー・・・それでもだめでしばらくはまる。
(PKであろうと同じ意味のフィールド=同名をつけたいポリシー)
対処法
結局結合先のテーブル情報はつかわないので、t_projectに絞った。
$projects = TProject:::select(DB::raw('t_project.*'))
->leftJoin('t_result', function ($join) use ( $userId) {
$join->on('t_project.id', '=', 't_result.project_id')
->where('t_result.user_id', '=', $userId);
})
->orderBy('t_result.amount', 'desc')->get();
正直、rawとか絶対つかいたくないっていうかテーブル名をここにベタ書きとか未だにEloquentのメソッド(staticじゃないと使えないもの)とLaravelのクエリビルダとの境がわからなくてさっぱり仲良くなれなくていちいち調べるから実装時間がかかってしょうがなくてどうにも・・・