web-dev-qa-db-fra.com

laravel avec méthode () et méthode load ()

J'ai vraiment essayé de comprendre la différence entre la méthode with() et la méthode load(), mais je n'ai pas vraiment compris.

Comme je le vois, utiliser la méthode with() est "meilleur" car je charge la relation avec impatience. Il semble que si j’utilise load(), je charge la relation comme si j’utilisais la hasMany() (ou toute autre méthode liée à la relation entre objets). 

Est-ce que je me trompe? 

30
kfirba

Tous deux obtiennent les mêmes résultats finaux: charger avec impatience un modèle associé sur le premier. En fait, ils exécutent tous les deux exactement les mêmes requêtes. La principale différence est que with() eager charge le modèle associé dès le début, immédiatement après la requête initiale (all(), first() ou find(x), par exemple); Lorsque vous utilisez load(), vous exécutez d'abord la requête initiale, puis chargez la relation avec impatience ultérieurement.

"Désireux" signifie ici que nous associons tous les modèles associés pour un ensemble de résultats particulier en utilisant une seule requête, au lieu de devoir exécuter n requêtes, où n est le nombre d'éléments dans l'ensemble initial.


Chargement rapide avec with()

Si nous voulons charger avec with(), par exemple:

$users = User::with('comments')->get(); 

... si nous avons 5 utilisateurs, les deux requêtes suivantes sont exécutées immédiatement:

select * from `users`
select * from `comments` where `comments`.`user_id` in (1, 2, 3, 4, 5)

... et nous aboutissons à une collection de modèles auxquels les commentaires sont attachés au modèle utilisateur. Nous pouvons donc faire quelque chose comme $users->comments->first()->body.


Chargement paresseux "paresseux" avec load()

Ou bien, nous pouvons séparer les deux requêtes, d’abord en obtenant le résultat initial:

$users = User::all();

qui fonctionne:

    select * from `users`

Et plus tard, si nous décidons que nous avons besoin des commentaires associés pour tous ces utilisateurs, nous pouvons les charger après coup:

$users = $users->load('comments');

qui exécute la 2ème requête:

    select * from `comments` where `comments`.`user_id` in (1, 2, 3, 4, 5)

... et nous obtenons le même résultat, divisé en deux étapes. De nouveau, nous pouvons appeler $users->comments->first()->body pour obtenir le modèle correspondant pour n’importe quel élément.


Pourquoi utiliser load() contre with()? load() vous donne la possibilité de décider plus tard, en fonction de certaines conditions dynamiques, si vous devez ou non exécuter la seconde requête. Si, toutefois, il ne fait aucun doute que vous aurez besoin d'accéder à tous les éléments connexes, utilisez with(). (Les documents font également référence à un avantage de la mise en cache de l'utilisation de load (), mais je ne le connais pas; en fait, je pense que les résultats de load() ne peuvent pas être mis en cache.)


L’autre solution consiste à parcourir en boucle le jeu de résultats initial et à interroger une relation hasMany() pour chaque élément. Ceci finirait par exécuter n + 1 requêtes, ou 6 dans cet exemple. Le chargement rapide, qu’il soit effectué d’abord avec with() ou ultérieurement avec load(), n’exécute que les requêtes 2 .

64
damiani

@damiani La différence expliquée entre load() et with() également, mais il a déclaré que load() ne peut pas être mis en cache, je veux donc en dire quelques mots.

Supposons que nous ayons un article de blog et des commentaires. Et nous allons chercher ensemble et le mettre en cache.

$post = Cache::remember("post.".$slug,720,function()use($slug){
   return Post::whereSlug($slug)->with("comments")->first();
});

Mais s'il y a un nouveau commentaire et que nous voulons l'afficher immédiatement, nous devons vider le cache de publication et récupérer à nouveau la publication et les commentaires. Et cela provoque des requêtes inutiles. Imaginons qu'il existe d'autres requêtes pour les tags, les médias, les contributeurs de la publication, etc. Cela augmentera l'utilisation des ressources.

public function load($relations)
{
    $query = $this->newQueryWithoutRelationships()->with(
        is_string($relations) ? func_get_args() : $relations
    );

    $query->eagerLoadRelations([$this]);

    return $this;
}

Comme vous pouvez le voir ci-dessus, lorsque nous utilisons la méthode, elle charge une relation donnée et renvoie le modèle avec la relation extraite. Vous pouvez donc le renvoyer en dehors d'un rappel.

$post = Cache::remember("post.".$slug,720,function()use($slug){
   return Post::whereSlug($slug)->first();
});

$post = Cache::remember("post.relation.images.".$slug,720,function()use($post){
  return $post->load("images");
});

$post = Cache::remember("post.relation.comments".$slug,720,function()use($post){
   return $post->load("comments");
});

Donc, si nous les chargeons séparément, la prochaine fois que certains auront mis à jour, il vous faudra effacer le cache de relations spécifique et le récupérer à nouveau. Pas besoin d'aller chercher des messages, des tags, des images, etc. encore et encore. 

1
Teoman Tıngır