はじめに
私は株式会社qnoteにて、勉強会の幹事を務めております。
2023年度勉強会の珠玉のネタを2023Qiitaアドベントカレンダーに投稿していこうと思います。
対象者
この記事は下記のような人を対象にしています。
- 駆け出しエンジニア
- プログラミング初学者
結論
- find()とfirst()は動的プロパティがスマート
- get()やall()で取得したコレクションをforeach()で処理する場合はwith()を使う
解説
(例) User に複数の Post が紐づく「1対多」のリレーションを考えます。
use Illuminate\Database\Eloquent\Relations\HasMany;
class User extends Model
{
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
}
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Post extends Model
{
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}
返り値 | $q->posts()->get() | $q->posts()->first() | $q->posts | $q->with(’posts’) | |
---|---|---|---|---|---|
find() | 単一モデル・オブジェクト | ○ | ○ | ◎ | △(with()の有無でクエリ数変化なし) |
first() | 単一モデル・オブジェクト | ○ | ○ | ◎ | △(with()の有無でクエリ数変化なし) |
get() | コレクション | ×(コレクションにpostsが存在しない) | ×(コレクションにpostsが存在しない) | ×(コレクションにpostsが存在しない) | ○(foreachの外側で使うべし) |
all() | コレクション | ×(コレクションにpostsが存在しない) | ×(コレクションにpostsが存在しない) | ×(コレクションにpostsが存在しない) | ○(foreachの外側で使うべし) |
上記4種を使わない | ビルダー | ×(コレクションにpostsが存在しない) | ×(コレクションにpostsが存在しない) | ×(コレクションにpostsが存在しない) | ○(foreachの外側で使うべし) |
// find()とfirst()は動的プロパティを使うのがスマート。
$user1 = User::find(1);
$posts1 = $user1->posts;
$user2 = User::first();
$posts2 = $user2->posts;
// find()とfirst()はwith()使ってもいいが、クエリ発行数は一緒。
$user1 = User::with('posts')->find(1);
$posts1 = $user1->posts;
$user2 = User::with('posts')->first();
$posts2 = $user2->posts;
// find()とfirst()はwith()の記述位置に注意。
$user1 = User::find(1)->with('posts'); // 返り値がBuilder!!!
$user2 = User::first(1)->with('posts'); // 返り値がBuilder!!!
// get()とall()の場合はN+1問題解決のためにwith()を使用すること。
$users3 = User::with('posts')->get();
foreach ($users3 as $user3) {
$posts3 = $user3->posts;
}
$users4 = User::with('posts')->all();
foreach ($users4 as $user4) {
$posts4 = $user4->posts;
}
// get()とall()のNGケース
$users3 = User::get();
foreach ($users3 as $user3) {
$posts3 = $user3->posts; // N+1発生!!!
}
$users4 = User::all();
foreach ($users4 as $user4) {
$posts4 = $user4->posts; // N+1発生!!!
}
おわりに
with()の正しい使い方についてまとめました。
参考記事
【Laravel】データ取得 find・first・get・all の違いをしっかり理解 【比較】 - エンジニ屋.com(エンジニヤドットコム)
[Laravel] 動的プロパティと Eager Loading - Qiita