laravel with() 方法与 load() 方法
Posted
技术标签:
【中文标题】laravel with() 方法与 load() 方法【英文标题】:laravel with() method versus load() method 【发布时间】:2014-11-18 07:16:17 【问题描述】:我真的很想了解with()
方法和load()
方法之间的区别,但无法真正理解。
在我看来,使用with()
方法“更好”,因为我渴望加载关系。似乎如果我使用load()
我加载关系就像我会使用hasMany()
(或与对象之间的关系相关的任何其他方法)。
我理解错了吗?
【问题讨论】:
【参考方案1】:两者都完成了相同的最终结果——渴望将相关模型加载到第一个模型上。事实上,它们都运行完全相同的两个查询。关键区别在于with()
在初始查询之后立即预先加载相关模型(例如all()
、first()
或find(x)
);当使用load()
时,首先运行初始查询,然后在稍后的某个时间点加载关系。
这里的“渴望”意味着我们为特定结果集关联所有相关模型只使用一个查询,而不是必须运行 n 个查询,其中 n 是初始集合中的项目数。
使用with()
进行预加载
如果我们使用with()
进行预加载,例如:
$users = User::with('comments')->get();
...如果我们有 5 个用户,以下两个查询会立即运行:
select * from `users`
select * from `comments` where `comments`.`user_id` in (1, 2, 3, 4, 5)
...我们最终得到了一个将 cmets 附加到用户模型的模型集合,因此我们可以执行$users->comments->first()->body
之类的操作。
使用load()
的“延迟”急切加载
或者,我们可以将两个查询分开,首先通过获取初始结果:
$users = User::all();
运行:
select * from `users`
然后,如果我们决定需要所有这些用户的相关 cmets,我们可以在事后立即加载它们:
$users = $users->load('comments');
运行第二个查询:
select * from `comments` where `comments`.`user_id` in (1, 2, 3, 4, 5)
...我们最终得到相同的结果,只是分为两个步骤。同样,我们可以调用$users->comments->first()->body
来获取任何项目的相关模型。
为什么使用load()
与with()
? load()
让您可以选择稍后根据某些动态条件决定是否需要运行第二个查询。但是,如果毫无疑问您需要访问所有相关项目,请使用with()
。
其中任何一个的替代方法是遍历初始结果集并查询每个项目的hasMany()
关系。这最终会运行 n+1 个查询,在本例中为 6。急切加载,无论是预先使用 with()
还是稍后使用 load()
完成,都只运行 2 个查询。
【讨论】:
谢谢!我还有一个问题,为什么我不使用急切加载并使用普通的hasMany()
方法? (我认为我的答案的一个解决方案是,每当我只与一个用户打交道时,我是否使用急切加载并不重要,因为它无论如何都会运行 2 个查询?)
这取决于您所追求的数据。如果您只对相关模型(在我们的示例中为 cmets)感兴趣,那么只需查询 hasMany()
关系方法:$users = User::find(1)->comments;
,它将仅返回有关 cmets 的信息,而不是用户的信息。但是,如果您还需要访问来自初始模型(用户)的数据,那么 $user = User::where('id','1')->with('comments')->get();
将为您提供一个集合,其中包含来自 User 表的数据和他们的相关 Comments。无论哪种方式,都会运行 2 个相同的查询,但结果集合不同。
load
可以像with
一样嵌套吗?喜欢这里 - ***.com/questions/47048804/…
withitem() 有什么作用?【参考方案2】:
@damiani 解释了load()
和with()
之间的区别,但他说load()
不可缓存,所以我想说两句。
假设我们有一篇与 cmets 相关的博客文章。我们正在一起获取并缓存它。
$post = Cache::remember("post.".$slug,720,function()use($slug)
return Post::whereSlug($slug)->with("comments")->first();
);
但是如果有新评论并且我们想立即显示它,我们必须清除帖子缓存并再次一起获取帖子和 cmets。这会导致不必要的查询。让我们认为还有另一个查询标签、媒体、帖子的贡献者等。这将增加资源使用量..
public function load($relations)
$query = $this->newQueryWithoutRelationships()->with(
is_string($relations) ? func_get_args() : $relations
);
$query->eagerLoadRelations([$this]);
return $this;
正如您在上面看到的,当我们使用加载给定关系并返回具有获取关系的模型的方法时。所以你可以在回调之外返回它。
$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");
);
因此,如果我们单独加载它们,下次当它们中的一些更新时,您需要清除特定的关系缓存并再次获取它。无需一遍又一遍地获取帖子、标签、图像等。
【讨论】:
【参考方案3】:正如@damiani 所说,两者都完成了相同的最终结果——渴望将相关模型加载到第一个模型上。事实上,它们都运行完全相同的两个查询。关键区别在于 with() 在初始查询之后立即预先加载相关模型(例如 all()、first() 或 find(x));使用 load() 时,您首先运行初始查询,然后在稍后的某个时间点加载关系。
With() 和 load() 之间还有一个区别,使用 with() 时可以设置条件,但使用 load() 时不能这样做
例如:
ProductCategory::with('children')
->with(['products' => function ($q) use($SpecificID)
$q->whereHas('types', function($q) use($SpecificID)
$q->where('types.id', $SpecificID)
);
])
->get();
【讨论】:
以上是关于laravel with() 方法与 load() 方法的主要内容,如果未能解决你的问题,请参考以下文章
CSRF 令牌与 Laravel API 不匹配,使用 Digital Ocean Load Balancer with Sticky Session
$query->with() 正在工作,但 $query->load() 在 Laravel 中不起作用