Laravel

LaravelのEagerロード(ネストしたリレーション)にほんの少し詰まったのでメモした

LaravelでEagerロードをしようとした際に、ほんの少しだけ詰まったので備忘録的にまとめました。


はじめに

Laravelには、N+1クエリ問題の解決策として、Eagerロードが用意されています。

このEagerロードを、とあるケースで使おうとした際に、詰まったのでそれについて書いて行きます。

ではまずは、僕がLaravelのEagerロードで詰まったケースについて、まずは提示していきます。


サービス内容

典型的な求人システムの開発


DB設計

usersテーブル

id

name

email

password

companiesテーブル

id

name

email

password

jobsテーブル    

id

company_id

title

description

entriesテーブル  

id

user_id

job_id

企業(Company)が求人(Job)を作成し、ユーザー(User)が求人に応募(Entry)

することができる簡単な構成です。


どこで詰まったのか

やりたかったことは、ユーザーのマイページに、応募済みのすべての求人を表示することです。表示される求人には、企業名も表示したいので、企業名をEagerロードする必要がありました。

最初こんな感じで書きました。


UserController.php


public function entriedJobs()
{
$user = Auth::user();

//自分の応募情報をすべて取得する
$entries = App\Entry::where('user_id', $user->id)->get();
$entries->load('job');

//自分の応募情報から求人情報をリレーションですべて取得する
$jobs = [];
foreach ($entries as $entry) {
$jobs[] = $entry->job;
}

return view('user.entried-jobs', [
'user' => $user,
'jobs' => $jobs,
]);
}


ただこれでは、求人(Job)しかEagerロードできていません。企業情報(Company)もEagerロードしたいです。

最初は、以下のようにEagerロードしようとしましたが、ここではリレーションで求人情報を取得しているため、当然エラーがでます。なぜなら、EagerロードはEloquentの動的プロパティを使用した際にしか使えないためです。


UserController.php


$jobs = [];
foreach ($entries as $entry) {
$jobs[] = $entry->job;
}
$jobs->load('company');


あらためてLaravelのドキュメントを確認したところ、ネストしたリレーションをEagerロードする際には、以下のように「ドット」記法が使用できるようです。


UserController.php


public function entriedJobs()
{
$user = Auth::user();

$entries = App\Entry::where('user_id', $user->id)->get();
//ネストした遅延Eagerロード
$entries->load(['job', 'job.company']);

$jobs = [];
foreach ($entries as $entry) {
$jobs[] = $entry->job;
}

return view('user.entried-jobs', [
'user' => $user,
'jobs' => $jobs,
]);
}


参考:Laravel 5.7 Eloquent:リレーション