はじめに
この記事はプログラミング初学者による備忘録用の記事であり、また、少しでも他の初学者のお役に立てればと思い書いています。
今回は、Laravelのwith()とload()について再考したので、備忘録としてまとめておきたいと思います。
間違いなどがございましたら、ご指摘のほどよろしくお願い致します。
どちらもN+1問題を解決する
with()とload()、両者共に特定のモデルに関連するモデルをロードする際に、N+1問題を解決しつつロードすることが可能です。
ドキュメントでは、
with()がEager Loading
、
load()がLazy Eager Loading
と呼ばれています。
両者ともに、実行するクエリの内容は同じであり、最終的にはどちらも同じ結果を取得することができますが、クエリを実行する際の流れに違いがあります。
with()
特徴:
with()は、Eager Loadingと呼ばれ、最初のクエリ (all(), first(), find() など) の直後に特定のモデルに関するモデルを事前にロードします。
記述例:
<?php
namespace App\Models;
class User extends Authenticatable
{
public function getUserData()
{
$users = $this->with('posts')->get();
}
}
実行されるクエリ
select * from `users`
select * from `posts` where `posts`.`user_id` in (1, 2, 3)
上記の実行されるクエリは、同一のアクション内で実行されます。
また、データを取得後、Userモデルにpostsデータを関連付けたモデルのコレクションが完成するので、posts側のデータをカラム指定などで取得することができます。
・with()他の使用例
複数のテーブルからデータを取得
$this->with(['posts','users'])->get();
//with()の中で[]を使い複数指定します
特定のカラムのデータを取得
$this->with('users:id, name')->get();
//コロン(:)を使い、特定のカラムを指定します(IDは必ず含める必要があります)
ネストした先のテーブルのデータを取得
$this->with('posts.comments')->get();
//ピリオド(.)で繋げてネスト先のテーブルを指定します
取得するデータに条件付与、並び替えが可能
$this->with('posts')->where('user_id', $id)->get();
load()
特徴:
load()は、Lazy Eager Loadingと呼ばれ、特定のモデルに関連するモデルを取得する際に、実行するクエリを2つに分割します。
例えば、親モデルが既に取得された後に、リレーションシップをEager Loadingする必要があるかもしれません。
そのような場合に、特定のモデルに関連するモデルのデータを取得することが可能です。
つまり、動的な条件に基づいて後で決定するオプションを提供しています。
記述例:
<?php
namespace App\Models;
class User extends Authenticatable
{
public function getUserData()
{
$users = $this->get();
if($someCondition)
{
$users = $users->load('posts');
}
}
}
実行されるクエリ
select * from `users`
-- 2回に分けて実行される
select * from `posts` where `posts`.`user_id` in (1, 2, 3)
load()は、2回目のクエリを実行する必要があるかどうかを、動的な条件に基づいて後で決定するオプションを提供します。
制約を付けることが可能
with()と同様に、追加でクエリを発行することが可能です。
$author->load(['books' => function ($query) {
$query->orderBy('published_date', 'asc');
}]);
終わりに
関連するモデルの全ての項目にアクセスする必要があると予め分かっている場合などは、 with()を使用すべきなのかのと思っています。