eloquent - Laravel - Eager Loading Polymorphic Relation's Related Models -
eloquent - Laravel - Eager Loading Polymorphic Relation's Related Models -
i can eager load polymorphic relations/models without n+1 issues. however, if seek access model related polymorphic model, n+1 problem appears , can't seem find fix. here exact setup see locally:
1) db table name/data
history
companies
products
services
2) models
// history class history extends eloquent { protected $table = 'history'; public function historable(){ homecoming $this->morphto(); } } // company class company extends eloquent { protected $table = 'companies'; // each company has many products public function products() { homecoming $this->hasmany('product'); } // each company has many services public function services() { homecoming $this->hasmany('service'); } } // product class product extends eloquent { // each product belongs company public function company() { homecoming $this->belongsto('company'); } public function history() { homecoming $this->morphmany('history', 'historable'); } } // service class service extends eloquent { // each service belongs company public function company() { homecoming $this->belongsto('company'); } public function history() { homecoming $this->morphmany('history', 'historable'); } }
3) routing
route::get('/history', function(){ $histories = history::with('historable')->get(); homecoming view::make('historytemplate', compact('histories')); });
4) template n+1 logged becacuse of $history->historable->company->name, comment out, n+1 goes away.. need distant related company name:
@foreach($histories $history) <p> <u>{{ $history->historable->company->name }}</u> {{ $history->historable->name }}: {{ $history->historable->status }} </p> @endforeach {{ dd(db::getquerylog()); }}
i need able load company names eagerly (in single query) it's related model of polymorphic relation models product
, service
. i’ve been working on days can't find solution. history::with('historable.company')->get()
ignores company
in historable.company
. efficient solution problem be?
solution:
it possible, if add:
class="lang-php prettyprint-override">protected $with = ['company'];
to both service
, product
models. way, company
relation eager-loaded every time service
or product
loaded, including when loaded via polymorphic relation history
.
explanation:
this result in additional 2 queries, 1 service
, 1 product
, i.e. 1 query each historable_type
. total number of queries—regardless of number of results n
—goes m+1
(without eager-loading distant company
relation) (m*2)+1
, m
number of models linked polymorphic relation.
optional:
the downside of approach always eager-load company
relation on service
, product
models. may or may not issue, depending on nature of data. if problem, utilize trick automatically eager-load company
only when calling polymorphic relation.
add history
model:
public function gethistorabletypeattribute($value) { if (is_null($value)) homecoming ($value); homecoming ($value.'withcompany'); }
now, when load historable
polymorphic relation, eloquent classes servicewithcompany
, productwithcompany
, rather service
or product
. then, create classes, , set with
within them:
productwithcompany.php
class="lang-php prettyprint-override">class productwithcompany extends product { protected $table = 'products'; protected $with = ['company']; }
servicewithcompany.php
class="lang-php prettyprint-override">class servicewithcompany extends service { protected $table = 'services'; protected $with = ['company']; }
...and finally, can remove protected $with = ['company'];
base of operations service
, product
classes.
a bit hacky, should work.
laravel eloquent polymorphic-associations eager-loading polymorphism
Comments
Post a Comment