Description
- Laravel Version: 5.6.33
- PHP Version: 7.1
- Database Driver & Version: mysql 5.6.31
Short version of the description
When we have a model A
with a relation b()
that uses the withDefault() and the B
model has a relation c()
when we try and do
$rows = A::with('b.c');
foreach($rows as $row)
{
$row->b->c;
}
For every b
instance that is a default model and not a row in the database, when we do ->c
it will trigger a database query.
So if we have 50 $rows, where only 2 acutally have a b
related row
the eager loading will work only on the 2 existing b
rows and we will have 48 other queries trying to fetch the c
relation of the b
default models
Long version of the description and details:
The withDefault() eloquent method was added to make reduce the conditionals and make the code better.
But when i have a model like this
class Complaint extends Model
{
public function status()
{
return $this->belongsTo(Status::class)->withDefault();
}
}
And then when i want to display a grid of my complaints by doing something like this
class ComplaintsController extends Controller
{
public function index(Request $request)
{
$complaints = Complaint::with(['status.translations'])->get();
return view('modules.complaints.index', compact('complaints'));
}
}
<table>
...
<tr>
...
<!-- the ->name will get the name from the translation that matches the application locale -->
<td>{{ $complaint->status->name }}</td>
...
</tr>
...
</table>
The problem being is that for every Status
that is a default model and does not really exist when i try to fetch the name
from the translation a new query will be exectued.
So to avoid having N queries problem now i'm doing this in my blade template
<table>
...
<tr>
...
<!-- the ->name will get the name from the translation that matches the application locale -->
<td>{{ $complaint->status->exists ? $complaint->status->name : null }}</td>
...
</tr>
...
</table>
Which is basically the thing that the default models were addedd for (writing this conditions)
This has been brought up before and closed without a real solution from the laravel framework core team #24241
@jonnsl added a suggestion for solving this issue