Laravel - Éloquent «A», «Avec», «Où A-t-il» - Que signifient-ils?

212

J'ai trouvé le concept et la signification derrière ces méthodes un peu déroutants, est-il possible pour quelqu'un de m'expliquer quelle est la différence entre haset withest, dans le contexte d'un exemple (si possible)?

lukasgeiter
la source

Réponses:

558

Avec

with()est pour un chargement rapide . Cela signifie essentiellement que, le long du modèle principal, Laravel préchargera la ou les relations que vous spécifiez. Cela est particulièrement utile si vous avez une collection de modèles et que vous souhaitez charger une relation pour chacun d'eux. Parce qu'avec un chargement rapide, vous n'exécutez qu'une seule requête DB supplémentaire au lieu d'une pour chaque modèle de la collection.

Exemple:

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
}

A

has()consiste à filtrer le modèle de sélection en fonction d'une relation. Il agit donc de manière très similaire à une condition WHERE normale. Si vous utilisez uniquement has('relation')cela signifie que vous souhaitez uniquement obtenir les modèles qui ont au moins un modèle lié dans cette relation.

Exemple:

User > hasMany > Post

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

Où est

whereHas()fonctionne de la même manière que has()mais vous permet de spécifier des filtres supplémentaires pour le modèle associé à vérifier.

Exemple:

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
la source
101
+1, réponse très utile! Notez également que tout with('relation')inclura les données de la table connexe dans la collection retournée, has('relation')et whereHas('relation')ne pas inclure les données de la table correspondante. Vous devrez donc peut-être appeler à la fois with('relation')ainsi que has()ou whereHas().
Soulriser
1
Greet Answer, Comment accéder au modèle parent à partir du modèle de relation, par exemple ici comment rechercher un post-modèle basé sur les attributs du modèle utilisateur
hussainfrotan
@BhojendraNepal Malheureusement, il ne semble pas y avoir grand-chose à ce sujet dans les documents ... C'est tout ce que j'ai trouvé (c'est quelques paragraphes plus bas)
lukasgeiter
@hussainfrotan de la même manière, utilisez whereHassur la relation utilisateur lors de la requête post.
Michael Tsang
Curieux, dans la documentation Laravel: laravel.com/docs/5.8/eloquent-relationships , lors de son utilisation whereHasutilise use Illuminate\Database\Eloquent\Builder;ce qui est alors avec function(Builder $query). La plupart des exemples que j'ai vus, utilisent le Builder, passez simplement la requête $, quelle est la bonne façon?
Guntar
8

Le document a déjà expliqué l'utilisation. J'utilise donc SQL pour expliquer ces méthodes

Exemple:


En supposant qu'il y en Order (orders)a plusieurs OrderItem (order_items).

Et vous avez déjà construit la relation entre eux.

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

Ces trois méthodes sont toutes basées sur une relation .

Avec


Résultat: with() retourne l'objet modèle et ses résultats associés.

Avantage: c'est un chargement rapide qui peut éviter le problème N + 1 .

Lorsque vous utilisez Eloquent Builder suivant:

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

Laravel change ce code en seulement deux 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...);

Et puis laravel fusionne les résultats du deuxième SQL comme différents des résultats du premier SQL par clé étrangère . Enfin, retournez les résultats de la collecte.

Donc, si vous avez sélectionné des colonnes sans la clé étrangère en fermeture, le résultat de la relation sera vide:

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
  }...
}]

A


Hasretournera l'objet du modèle que sa relation n'est pas vide .

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

Laravel change ce code en un SQL :

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

Où est


whereHaset les orWhereHasméthodes pour mettre des whereconditions à vos hasrequêtes. Ces méthodes vous permettent d'ajouter des contraintes personnalisées à une contrainte de relation .

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

Laravel change ce code en un SQL :

select * from `orders` where exists (
    select * 
    from `order_items` 
    where `orders`.`id` = `order_items`.`order_id` and `status` = 1
)
TsaiKoga
la source