()方法与 load()方法

我真的试图理解 with()方法和 load()方法之间的区别,但是不能真正理解。

在我看来,使用 with()方法“更好”,因为我渴望加载关系。看起来,如果我使用 load(),我加载这个关系,就像我使用 hasMany()(或任何其他与对象之间的关系相关的方法)一样。

我说错了吗?

153583 次浏览

Both accomplish the same end results—eager loading a related model onto the first. In fact, they both run exactly the same two queries. The key difference is that with() eager loads the related model up front, immediately after the initial query (all(), first(), or find(x), for example); when using load(), you run the initial query first, and then eager load the relation at some later point.

"Eager" here means that we're associating all the related models for a particular result set using just one query, as opposed to having to run n queries, where n is the number of items in the initial set.


Eager loading using with()

If we eager load using with(), for example:

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

...if we have 5 users, the following two queries get run immediately:

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

...and we end up with a collection of models that have the comments attached to the user model, so we can do something like $users->comments->first()->body.


"Lazy" eager loading using load()

Or, we can separate the two queries, first by getting the initial result:

$users = User::all();

which runs:

select * from `users`

And later, if we decide that we need the related comments for all these users, we can eager load them after the fact:

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

which runs the 2nd query:

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

...and we end up with the same result, just split into two steps. Again, we can call $users->comments->first()->body to get to the related model for any item.


Why use load() vs. with()? load() gives you the option of deciding later, based on some dynamic condition, whether or not you need to run the 2nd query. If, however, there's no question that you'll need to access all the related items, use with().


The alternative to either of these would be looping through the initial result set and querying a hasMany() relation for each item. This would end up running n+1 queries, or 6 in this example. Eager loading, regardless of whether it's done up-front with with() or later with load(), only runs 2 queries.

@damiani Explanied difference between load() and with() as well but he said load() is not cacheable so I wanna say couple words about it.

Let assume we have a blog post and related with comments. And we're fetching together and caching it.

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

But if there is a new comment and we want to display it immediately, we have to clear post cache and fetch post and comments together again. And that causes unnecessary queries. Lets think there are another queries for tags, media, contributors of the post etc. it will increase amount of resource usage..

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


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


return $this;
}

As you can see above when we use the method it loads given relation and returns model with fetched relation. So you can return it outside of a callback.

$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");
});

So if we load them seperatly, next time when some of them updated all you need to do clear specific relation cache and fetch it again. No need to fetch post, tags, images etc. over and over.

As @damiani said, Both accomplish the same end results—eager loading a related model onto the first. In fact, they both run exactly the same two queries. The key difference is that with() eager loads the related model up front, immediately after the initial query (all(), first(), or find(x), for example); when using load(), you run the initial query first, and then eager load the relation at some later point.

There is one more difference between With() & load(), you can put the conditions when using with() but you can't do the same in case of load()

For example:

ProductCategory::with('children')
->with(['products' => function ($q) use($SpecificID) {
$q->whereHas('types', function($q) use($SpecificID) {
$q->where('types.id', $SpecificID)
});
}])
->get();