Laravel - Elokwentny „Has”, „With”, „WhereHas” - co one oznaczają?

211

Znalazłem pojęcie i znaczenie za tych metod, aby być trochę mylące, to jest możliwe, aby ktoś mi wyjaśnić, jaka jest różnica między hasi withjest w tym kontekście przykład (jeśli to możliwe)?

lukasgeiter
źródło

Odpowiedzi:

555

Z

with()jest do chętnego ładowania . Zasadniczo oznacza to, że zgodnie z głównym modelem Laravel wstępnie załaduje określone relacje. Jest to szczególnie przydatne, jeśli masz kolekcję modeli i chcesz załadować relację dla wszystkich z nich. Ponieważ przy chętnym ładowaniu uruchamiasz tylko jedno dodatkowe zapytanie DB zamiast jednego dla każdego modelu w kolekcji.

Przykład:

User > hasMany > Post

$users = User::with('posts')->get();
foreach($users as $user){
    $users->posts; // posts is already loaded and no additional DB query is run
}

Ma

has()jest filtrowanie wybranego modelu na podstawie relacji. Więc działa bardzo podobnie do normalnego GDZIE. Jeśli po prostu użyjesz has('relation'), oznacza to, że chcesz tylko uzyskać modele, które mają co najmniej jeden powiązany model w tej relacji.

Przykład:

User > hasMany > Post

$users = User::has('posts')->get();
// only users that have at least one post are contained in the collection

WhereHas

whereHas()działa w zasadzie tak samo, has()ale pozwala określić dodatkowe filtry dla powiązanego modelu do sprawdzenia.

Przykład:

User > hasMany > Post

$users = User::whereHas('posts', function($q){
    $q->where('created_at', '>=', '2015-01-01 00:00:00');
})->get();
// only users that have posts from 2015 on forward are returned
lukasgeiter
źródło
101
+1, bardzo pomocna odpowiedź! Należy również zauważyć, że while with('relation')będzie zawierać dane tabeli pokrewnej w zwróconej kolekcji has('relation')i niewhereHas('relation') będzie zawierał danych tabeli pokrewnej. Więc może trzeba zadzwonić zarówno jak i . with('relation')has()whereHas()
Soulriser,
1
Pozdrów odpowiedź, jak uzyskać dostęp do modelu nadrzędnego z modelu relacji, na przykład tutaj, jak wyszukiwać model postu na podstawie atrybutów modelu użytkownika
hussainfrotan
@BojeojeraNepal Niestety, nie wydaje się, aby było dużo w tej dokumentacji ... To wszystko, co znalazłem (kilka akapitów poniżej)
lukasgeiter
@ hussainfrotan w ten sam sposób, używaj whereHasrelacji z użytkownikami podczas wysyłania zapytań.
Michael Tsang,
Ciekawe, w dokumentacji Laravela: laravel.com/docs/5.8/eloquent-relationships , gdy używasz whereHastego, use Illuminate\Database\Eloquent\Builder;co wtedy jest function(Builder $query). Większość przykładów, które widziałem, używa kropki Builder, wystarczy podać zapytanie $, która jest właściwa metoda?
Guntar
8

Dokument wyjaśnił już użycie. Więc używam SQL do wyjaśnienia tych metod

Przykład:


Zakładając, że jest Order (orders)wiele OrderItem (order_items).

I już zbudowałeś relacje między nimi.

// App\Models\Order:
public function orderItems() {
    return $this->hasMany('App\Models\OrderItem', 'order_id', 'id');
}

Te trzy metody opierają się na relacji .

Z


Wynik: with() zwróć obiekt modelu i powiązane wyniki.

Zaleta: jest chętna do ładowania, która może zapobiec problemowi N + 1 .

Gdy używasz następującego Eloquent Buildera:

Order::with('orderItems')->get();

Laravel zmienia ten kod na tylko dwa SQL :

// get all orders:
SELECT * FROM orders; 

// get the order_items based on the orders' id above
SELECT * FROM order_items WHERE order_items.order_id IN (1,2,3,4...);

Następnie laravel scala wyniki drugiego SQL jako różne od wyników pierwszego SQL według klucza obcego . W końcu zwróć wyniki kolekcji.

Więc jeśli wybierzesz kolumny bez klucza obcego w zamknięciu, wynik relacji będzie pusty:

Order::with(['orderItems' => function($query) { 
           // $query->sum('quantity');
           $query->select('quantity'); // without `order_id`
       }
])->get();

#=> result:
[{  id: 1,
    code: '00001',
    orderItems: [],    // <== is empty
  },{
    id: 2,
    code: '00002',
    orderItems: [],    // <== is empty
  }...
}]

Ma


Haszwróci obiekt modelu, że jego związek nie jest pusty .

Order::has('orderItems')->get();

Laravel zmień ten kod na jeden SQL :

select * from `orders` where exists (
    select * from `order_items` where `order`.`id` = `order_item`.`order_id`
)

whereHas


whereHasi orWhereHasmetody ustalania wherewarunków dla twoich haszapytań. Te metody pozwalają dodawać niestandardowe wiązania do ograniczenia relacji .

Order::whereHas('orderItems', function($query) {
   $query->where('status', 1);
})->get();

Laravel zmień ten kod na jeden SQL :

select * from `orders` where exists (
    select * 
    from `order_items` 
    where `orders`.`id` = `order_items`.`order_id` and `status` = 1
)
TsaiKoga
źródło