Laravel - Eager Laden Polymorphe Relation Verwandte Modelle
Kann ich begierig laden polymorphe Beziehungen/Modelle, ohne jede n+1-Problemen. Jedoch, wenn ich versuche, auf ein Modell bezogen auf das polymorphe Modell, das n+1 problem angezeigt und ich kann nicht scheinen zu finden, a fix. Hier ist das genaue setup, um es zu sehen vor Ort:
1) DB-Tabelle, die Namen/Daten
history
companies
products
services
2) Modelle
//History
class History extends Eloquent {
protected $table = 'history';
public function historable(){
return $this->morphTo();
}
}
//Company
class Company extends Eloquent {
protected $table = 'companies';
//each company has many products
public function products() {
return $this->hasMany('Product');
}
//each company has many services
public function services() {
return $this->hasMany('Service');
}
}
//Product
class Product extends Eloquent {
//each product belongs to a company
public function company() {
return $this->belongsTo('Company');
}
public function history() {
return $this->morphMany('History', 'historable');
}
}
//Service
class Service extends Eloquent {
//each service belongs to a company
public function company() {
return $this->belongsTo('Company');
}
public function history() {
return $this->morphMany('History', 'historable');
}
}
3) Routing
Route::get('/history', function(){
$histories = History::with('historable')->get();
return View::make('historyTemplate', compact('histories'));
});
4) Vorlage mit n+1 angemeldet nur becacuse der $Geschichte->historable->company->name, Kommentar, n+1 geht Weg.. aber wir brauchen eine entfernte Verwandte name des Unternehmens:
@foreach($histories as $history)
<p>
<u>{{ $history->historable->company->name }}</u>
{{ $history->historable->name }}: {{ $history->historable->status }}
</p>
@endforeach
{{ dd(DB::getQueryLog()); }}
Ich muss in der Lage sein zu laden, den Namen des Unternehmens mit Spannung (in einer Abfrage), da es ein Verwandtes Modell, die polymorphe Beziehung Modelle Product
und Service
.
Ich habe schon seit Tagen, aber finde keine Lösung.
History::with('historable.company')->get()
ignoriert company
im historable.company
.
Was wäre eine effiziente Lösung für dieses problem sein?
InformationsquelleAutor der Frage Wonka | 2014-11-04
Du musst angemeldet sein, um einen Kommentar abzugeben.
Lösung:
Ist es möglich, wenn Sie hinzufügen:
sowohl die
Service
undProduct
Modelle. So, diecompany
Verhältnis ist gespannt-geladen jedes mal, wenn einService
oder eineProduct
geladen wird, auch wenn geladen über die polymorphe Beziehung mitHistory
.Erklärung:
Dadurch wird eine zusätzliche 2 Abfragen, eine für
Service
und eine fürProduct
d.h. eine Abfrage für jedehistorable_type
. So Ihr Gesamtanzahl der Abfragen—unabhängig von der Anzahl der Ergebnissen
—geht ausm+1
(ohne eager-loading der Fernencompany
relation) zu(m*2)+1
wom
ist die Anzahl der Modelle, verbunden durch Ihre polymorphe Beziehung.Optional:
Der Nachteil dieses Ansatzes ist, dass Sie immer eager-load der
company
Bezug auf dieService
undProduct
Modelle. Dies kann oder kann nicht ein Problem sein, je nach Art Ihrer Daten. Wenn dies ein problem ist, könnten Sie diesen trick verwenden, um automatisch eager-loadcompany
nur beim Aufruf der polymorphen Bezug.Fügen Sie diese zu Ihrem
History
Modell:Nun, beim laden der
historable
polymorphe Beziehung, Eloquent Aussehen wird für die KlassenServiceWithCompany
undProductWithCompany
eher alsService
oderProduct
. Dann erstellen Sie diese Klassen, und legen Siewith
in Ihnen:ProductWithCompany.php
ServiceWithCompany.php
...und schließlich können Sie entfernen
protected $with = ['company'];
von der BasisService
undProduct
Klassen.Etwas hacky, aber es sollte funktionieren.
InformationsquelleAutor der Antwort damiani
Sie trennen die Sammlung, dann faul eifrig laden jeden ein:
Wahrscheinlich ist es nicht die beste Lösung, das hinzufügen
protected $with = ['company'];
wie vorgeschlagen von @damiani ist wie eine gute Lösung, aber es hängt von Ihrem business-Logik.InformationsquelleAutor der Antwort Razor
Pull-Request #13737 und #13741 das Problem behoben.
Aktualisieren Sie einfach Ihren Laravel-version und den folgenden code
Funktioniert wie erwartet.
InformationsquelleAutor der Antwort João Guilherme
Bin ich mir nicht 100% sicher, weil es schwer ist, neu zu erstellen Ihren code in meinem system, aber vielleicht
belongTo('Company')
solltemorphedByMany('Company')
. Sie könnten auch versuchenmorphToMany
. Ich war in der Lage, eine komplexe polymorphe Beziehung problemlos zu laden, ohne mehrere Anrufe. ?InformationsquelleAutor der Antwort dwenaus
Als João Guilherme erwähnt, wurde dieses Problem behoben in version 5.3 Aber ich habe festgestellt, mich vor dem gleichen Fehler in einer App, wo es nicht sinnvoll ist, zu aktualisieren. Also ich habe eine Methode überschreiben, wird das Update auf Legacy-APIs. (Danke Johann, für den Hinweis mich in die richtige Richtung zu produzieren.)
Erstellen Sie zunächst Ihre Klasse Überschreiben:
Als Nächstes werden Sie brauchen etwas, mit Ihrer Model-Klassen tatsächlich sprechen Sie mit Ihrem Inkarnation von MorphTo eher als Redegewandt. Dies kann entweder erreicht werden, indem ein Merkmal angewendet, um jedes Modell, oder ein Kind von Illuminate\Database\Eloquent\Modell wird erweitert, indem Sie Ihre Modell-Klassen anstelle von Illuminate\Database\Eloquent\Model direkt. Ich habe dieses in einem Zug. Aber im Fall, dass Sie wählte, um es eine Kind-Klasse, ich habe in dem Teil, wo ihm lässt sich der name als ein heads-up, das ist etwas, das Sie brauchen, zu betrachten:
InformationsquelleAutor der Antwort Claymore