Reputation: 412
I have two models, Box and BoxLocations. Box
has a hasMany
relation to BoxLocations
and BoxLocations
has a belongsTo
relationship to Box
.
BoxLocations
also has an attribute that is appended to the model that required a single piece of information from the Box relation.
I have noticed that when calling Box::with(['BoxLocations']->)all();
I see that the BoxLocations
model is re-loading the Box relationship. This is happening for each BoxLocation
(50 odd times)
Does laravel not track that the Box was already loaded from the initial Box::with(['BoxLocations']->)all();
request and then pass this to the BelongsTo relationship?
I am trying to optimise a web system and when the taken attribute is loaded (annoyingly its required every time its loaded as well) its causing 50 odd hits to the database for the same Box model it has already loaded.
If laravel does not do this - is there a better way in which to achieve the above?
Upvotes: 0
Views: 1601
Reputation: 2636
Laravel uses eager loading when you use the with()
method.
When accessing Eloquent relationships as properties, the relationship data is "lazy loaded". This means the relationship data is not actually loaded until you first access the property. However, Eloquent can "eager load" relationships at the time you query the parent model. Eager loading alleviates the N + 1 query problem.
So if you do this:
$boxes = Box::with('BoxLocations')->get();
It will load the relations already, but lets' say you do this:
$boxes = Box::all();
foreach($boxes as $box)
{
echo box->boxlocation->name;
}
If you have 50 Boxes, this loop would run 51 queries.
But when you use the with
method and eager load the relation, this loop will run only 2 queries.
You could also use Lazy Eager Loading and decide when you want to load the relationship
Upvotes: 1