De ce?

Jonathan Reinink a scris o postare excelenta pe blog despre Optimizarea relatiilor circulare in Laravel

Prin setarea manuala a relatiei (apartine) unui model parinte pe modelele secundare aferente (areMany), puteti salva interogari inutile pentru modelul parinte – atunci cand copilul are nevoie de o instanta a modelului parinte.

Acest lucru pare probabil confuz, asa ca cititi doar postarea de pe blog. E foarte bine.

Abordarea lui Jonathan sugereaza utilizarea a ceva de genul acesta:

$ category-> products-> each-> setRelation (‘categorie’, $ categorie);

Acest lucru functioneaza, dar nu este foarte curat si exista cazuri in care nu functioneaza. De exemplu, despre crearea modelului.

Daca accesati modelul parinte in crearea si salvarea de evenimente pe copii, abordarea -> fiecare-> setRelation () nu va va ajuta deloc. (Si daca creati o aplicatie complexa cu Laravel Nova, exista mari sanse sa folositi o multime de astfel de evenimente.)

Exemplu practic si repere

Am o aplicatie de comert electronic in care o comanda are modele secundare: OrderProduct, OrderStatus si OrderFee (ganditi-va la costurile de expediere, taxele de plata etc.).

Cand unele dintre aceste modele sunt create (crearea unui eveniment Elocvent), acestea acceseaza modelul parinte.

De exemplu, OrderProducts isi convertesc preturile in $ this-> order-> currency. OrderFees verifica alte taxe de comanda si impiedica crearea lor daca exista deja o taxa cu acelasi cod (astfel incat sa nu puteti avea, sa zicem, costul de expediere numarat de doua ori). Etc.

Acest lucru are ca rezultat crearea comenzilor costisitoare, rezultand o cantitate mare de n + 1 interogari.

Etalon

Nu am efectuat o cantitate imensa de teste, asa ca nu voi prezenta diferentele de timp aici. Voi vorbi doar despre numarul de interogari in baza de date.

Am creat o comanda cu 6 produse.

Aceasta este cantitatea de interogari facute cu hasMany obisnuit ()

Si acum doar inlocuiesc toate aceste apeluri:

returneaza $ this-> hasMany (..

xxx gratis en español follando rico
mamadas por dinero pornoxxxxx
follando a mi hija porno español jovencitas
se folla a su cuñada comic porno español
hombres pajeandose videos porno abuelas
folladoras cincuentonas follando
porno español años 70 xxx abuelas
todoporno pono gay
suegras peludas danna paola desnuda
copilacion de mamadas culos porno
porno gay españoles corridas en la garganta
madres haciendo pajas a sus hijos chochitos jovencitos
penes enormes orgias caseras
randy dave intercambio parejas amateur
comiendo tetas el video porno mas visto en internet
masajes eroticos chinos follando en el campo
maduras gordas desnudas pajas caseras
porno casero colombiano cachondas españolas
porno muy duro me hace una paja
super maduras videos porno caseros españoles

.);

cu aceste apeluri

returneaza $ this-> hasManyWithInverse (…, ‘order’);

in interiorul modelului de comanda.

Si aceasta este cantitatea de interogari facute cu hasManyWithInverse ()

Consultati reducerea numarului de interogari.

Durata a fost, de asemenea, scazuta de la 114 ms la 45 ms pe masina mea, desi retineti ca nu am efectuat acest test de un milion de ori pentru a calcula o durata medie, astfel incat aceasta valoare de referinta ar putea sa nu fie foarte precisa.

Acest lucru este destul de impresionant pentru o imbunatatire gratuita care necesita doar schimbarea catorva apeluri simple la o metoda similara .

Dar retineti ca acesta nu este un glont de argint pentru rezolvarea tuturor interogarilor n + 1. Dupa cum puteti vedea, chiar si cu acest lucru implementat, aplicatia mea are inca multe interogari duplicate. (Desi nu toate sunt n + 1 neintentionate, deoarece exista cateva apeluri $ this-> refresh () pentru a mentine comanda actualizata dupa tranzitiile de stare).

Instalare

Laravel 6.x, 7.x si 8.x este acceptat.

compozitor necesita stancl / laravel-hasmanywithinverse

Utilizare

App spatiu de nume; utilizati Stancl \ HasManyWithInverse \ HasManyWithInverse; clasa Order extinde Model {use HasManyWithInverse; produse de functie publica () {// „comanda” este numele relatiei din celalalt model, vezi mai jos returneaza $ this-> hasManyWithInverse (OrderProduct :: class, „order”); }} clasa OrderProduct extinde Model {ordine functie publica () {return $ this-> belongTo (Order :: class); }}

Poate doriti sa folositi trasatura intr-un model de baza Elocvent si apoi sa utilizati $ this-> hasManyWithInverse () fara sa va ganditi la trasaturi in modelele specifice.

Detalii

Internele (simple) ale pachetului sunt doar metode copiate din codul sursa Elocvent, cu cateva linii adaugate la acestea. Semnatura metodei hasManyWithInverse () este aceeasi cu hasMany () (puteti seta $ foreignKey si $ localKey), cu exceptia celui de-al doilea argument ($ invers) a fost adaugat pentru a va permite sa definiti numele relatiei pe modelul copil si Ultimul argument ($ config) a fost adaugat pentru a va permite sa configurati comportamentul setarii relatiei.

Acest pachet stabileste relatia parinte la copii atat la crearea copiilor ($ copil = $ parinte-> copii () -> creati ()), cat si la rezolvarea copiilor parintilor ($ copii = $ parinte-> copii). Puteti personaliza acest comportament pentru fiecare relatie.

Pentru a dezactiva setarea relatiei in timpul crearii copilului , procedati astfel:

class Parent extinde Model {public function children () {return $ this-> hasManyWithInverse (Child :: class, ‘parent’, null, null, [‘setRelationOnCreation’ => false]); }}

Pentru a dezactiva setarea relatiei in timpul rezolvarii copilului , procedati astfel:

class Parent extinde Model {public function children () {return $ this-> hasManyWithInverse (Child :: class, ‘parent’, null, null, [‘setRelationOnResolution’ => false]); }}

De asemenea, puteti trece un apelabil ca valoare de configurare. Acest lucru este util daca doriti sa dezactivati acest comportament la anumite cereri. Vezi exemplul de mai jos.

Laravel Nova

Este o idee buna sa dezactivati setarea relatiei pe rezolutie pentru solicitarile Nova. Au tendinta de a face multe intrebari si acest lucru poate incetini pagina (sau poate duce la 502 de erori).

Iata un exemplu de implementare folosind un model de baza si adaugand config pentru a filtra solicitarile Nova.

clasa abstracta Model extinde EloquentModel {use HasManyWithInverse {hasManyWithInverse ca originalHasManyWithInverse; } functia publica areMulteCuInvers ($ asociata, $ inversa, $ strainaKey = null, $ localKey = null, $ config = []) {$ config = array_merge ([‘setRelationOnResolution’ => functie () {if (request () -> route () && in_array (‘nova’, request () -> route () -> middleware ())) {return false;}}], $ config); returneaza $ this-> originalHasManyWithInverse ($ related, $ invers, $ foreignKey, $ localKey, $ config); }}