LaravelでModelを使ったDBの操作の仕組み
📖 目次
クエリビルダーとインスタンス
// クエリビルダー(まだDBに問い合わせていない)
Plan::where('user_id', 1) → where('date', $date)
// get()で初めてDBに問い合わせてインスタンスが生まれる
→ get(); // → PlanモデルのインスタンスのCollection
メソッドはインスタンスがないと実行できない。
プロパティとメソッド
プロパティ → テーブルのカラムに対応
$plan → title // plansテーブルのtitleカラム
$plan → goal_value // plansテーブルのgoal_valueカラム
メソッド(リレーション) → Plan.phpに自分で定義したもの
$plan → children // Plan.phpにchildren()を定義
$plan → result // Plan.phpにresult()を定義
$plan → unitName // Plan.phpにunitName()を定義
見分け方は $fillable に書いてあるものがプロパティ、function で定義したものがメソッド。
リレーションの種類
$plan → children // HasMany → Collectionで複数返る
$plan → result // HasOne → 1件のインスタンスが返る
$plan → unitName // BelongsTo → 1件のインスタンスが返る
withとN+1問題
withなし(N+1問題)
$plans = Plan::where(...) → get();
// SQL1回: SELECT * FROM plans
foreach ($plans as $plan) {
$plan → result; // planの数だけSQL発行
$plan → unitName; // planの数だけSQL発行
}
// planが10件 → 合計21回SQL
withあり
$plans = Plan::where(...) → with(['result', 'unitName']) → get();
// SQL1回: SELECT * FROM plans
// SQL1回: SELECT * FROM results WHERE plan_id IN (1,2,3...)
// SQL1回: SELECT * FROM mst_names WHERE cd IN (...)
// 合計3回
foreach ($plans as $plan) {
$plan → result; // メモリから返す(SQL発行なし)
$plan → unitName; // メモリから返す(SQL発行なし)
}
with('children')の仕組み
→ with('children') // 文字列'children'を渡している
Laravelが 'children' という文字列を見て内部で children() メソッドを呼び出してSQLを組み立てる。だからメソッドの定義が必要。
// メソッドがないとエラー
Plan::with('children') → get(); // ❌ childrenって何?
// メソッドがあるから動く
public function children(): HasMany
{
return $this → hasMany(Plan::class, 'parent_id');
}
Plan::with('children') → get(); // ✅
children()は自己結合
public function children(): HasMany
{
return $this → hasMany(Plan::class, 'parent_id', 'id');
}
-- 同じplansテーブルをparent_idで自己参照
SELECT * FROM plans WHERE parent_id = {親のid}
同じ plans テーブルを parent_id で自己参照している。
JOINとwithの違い
JOIN → フラットな結果、親が子の数だけ重複
parent.id | parent.title | child.title
1 | Laravel学習 | ルーティング理解
1 | Laravel学習 | Blade学習
2 | 運動する | ランニング
with → 階層構造、親は重複しない
$plans[0] title=Laravel学習
children[0] title=ルーティング理解
children[1] title=Blade学習
$plans[1] title=運動する
children[0] title=ランニング
.NETで言うとJOINの結果をDataTableで受けて親子に組み立て直す作業をLaravelが自動でやってくれるイメージ。
$plan->unitName? → cd_content
$plan → unitName // BelongsTo → MstNameの1件のインスタンス
$plan → unitName → cd_content // そのインスタンスのcd_contentカラム
// ? → はnullの場合にエラーにならないようにする
$plan → unitName? → cd_content
// unitNameがnull(unit_cdが未設定)でもエラーにならずnullを返す
? → を使わないと、unitName が null のときにエラーになる。
hasOneの外部キー規約
public function result(): HasOne
{
return $this → hasOne(Result::class);
// 省略しているが実際は
return $this → hasOne(Result::class, 'plan_id', 'id');
// モデル名_id が外部キーの規約
}
SELECT * FROM results WHERE plan_id = {planのid} LIMIT 1
モデル名_id が外部キーの規約。Result → plan_id が自動で使われる。