[英]Laravel: What is the purpose of the `loadMissing` function?
Laravel文档中Eager Loading部分的第一句是:
当访问Eloquent关系作为属性时,关系数据是“延迟加载”。 这意味着在您首次访问该属性之前,实际上不会加载关系数据。
在本节的最后一段中说明:
要仅在尚未加载关系时加载关系,请使用loadMissing方法:
public function format(Book $book)
{
$book->loadMissing('author');
return [
'name' => $book->name,
'author' => $book->author->name
];
}
但我没有看到$book->loadMissing('author')
。 这是在做什么吗?
如果我删除这一行会有什么区别? 根据第一句话, $book->author->name
的作者无论如何都会加入懒惰 ,对吧?
非常好的问题; 通过阅读文档可以立即反映出微妙的差异。
您正在使用loadMissing()
将“ Lazy Eager Loading ”与使用模型上的魔术属性进行“延迟加载”进行比较。
顾名思义,唯一的区别是:
因此,实际上,除非您希望在使用之前显式加载关系,否则没有区别。
值得注意的是, load
和loadMissing
方法使您有机会通过传递闭包来自定义关系加载逻辑,该闭包在使用魔术属性时不是一个选项。
$book->loadMissing(['author' => function (Builder $query) {
$query->where('approved', true);
}]);
除非您在模型上定义approvedAuthor
关系(这是一种更好的做法),否则使用$book->author
无法实现“加载缺失已批准作者(如果尚未加载 )”。
直接回答你的问题; 是的,如果你删除将没有任何区别:
$book->loadMissing('author');
在该特定示例中,因为它在加载后立即使用。 但是,可能很少有用户希望在使用之前加载关系。
因此,要概述关系加载方法的工作原理:
通过使用with()
您可以在查询父模型时“急切加载”关系:
$book = Book::with('author')->find($id);
在已经检索父模型之后急切地加载关系:
$book->load('author');
这也可能只用于加载遗漏的方法:
$book->loadMissing('author');
与load()
方法相反, loadMissing()
方法通过给定的关系进行过滤,并且只有在尚未加载时才会 “ loadMissing()
”加载它们。
通过接受闭包,这两种方法都支持自定义关系加载逻辑。
通过使用魔法属性实现的延迟加载是为了方便开发人员。 它会根据其使用情况加载关系,这样您就不需要事先加载它。
@rzb也在他的回答中提到了一个非常好的观点。 看一看。
我相信已接受的答案是缺少一个可能误导某些事实的重要事实:您无法对集合运行loadMissing($relation)
。
这很重要,因为大多数惰性加载关系的用例是当你已经有一个集合并且你不想提交n + 1 sin时 - 即在循环中不必要地多次击中DB。
因此,虽然您可以对集合使用load($relation)
,但如果您只想在以前尚未加载关系的情况下执行此操作,那么您将失去运气。
让我们说你有多种关系。
本书属于作者,本书属于出版商。
所以首先你可以加载一个关系。
$books->load('author');
后来在某种情况下你想加载另一个关系。
$book->loadMissing('publisher');
但我没有看到$ book-> loadMissing('author');的目的。 这是在做什么吗? 如果我删除这一行会有什么区别? 根据第一句话,$ book-> author-> name中的作者无论如何都会加入懒惰,对吧?
假设说
public function format(Book $book)
{
//book will not have the author relationship yet
return [
'name' => $book->name, //book will not have the author relationship loaded yet
'author' => $book->author->name //book will now have the author relationship
];
}
上面和下面的代码之间的区别是加载关系的时间以及对属性的控制程度。
public function format(Book $book)
{
$book->loadMissing('author'); // book will now have the author relationship
return [
'name' => $book->name, // book have the author relationship loaded
'author' => $book->author->name // book have the author relationship loaded
];
}
这里的两个答案都很好地涵盖了技术差异,所以我先给大家介绍一下。 但“为什么”并不是很明显。
我最近发现自己的一些东西是Eloquent非常擅长给你足够的绳索来吊死自己。 通过抽象开发人员远离生成的实际SQL查询,特别是使用动态属性,很容易忘记当数据库命中对您的性能造成的损害超出他们的需要时。
这就是事情。 对1000个值使用IN()
语句的一个查询与在一个值上运行的一个查询执行的执行时间大致相同。 SQL非常擅长它的功能 - 通常会打开和关闭数据库连接。 这有点像去杂货店购物,通过每个项目进行一次市场之旅,而不是一次完成所有这一切。 Eager-loads使用IN语句。
延迟加载适用于您为服务器的RAM处理太多数据以应对的情况,并且在我看来,对其他方面并不好。 它在任何给定时刻只处理一个条目。 但它每次重新连接。 我不能告诉你我看过Transformer类的次数,它应该只负责重新格式化数据而不是检索数据,利用这些动态属性并且没有意识到数据不存在。 我看到改进只是通过在调用Transformer之前添加一行预先加载来将执行时间从30分钟缩短到30秒。
(顺便说一句,批处理可能被认为是快乐的媒介,而Eloquent的chunk()
方法也提供了这种方法。)
更直接地回答你的问题; 如果你正在处理一个一对一关系的实例,并且它只在一个地方使用,那么在功能上, load
, loadMissing
或延迟加载的动态属性之间没有区别。 但是如果你有多对多,那么同时收集所有数据可能是值得的。 一本书可以有很多共同作者。 一位作者可以写很多书。 如果您即将完成大量任务,请在开始烹饪之前充分利用您的市场之旅。
如果你使用的话,它的意思是不重复查询要清楚它:load()2次查询将重复,即使关系存在
while:loadMissing()检查关系是否已加载。 它不会重复查询。 因为[load()或with()] = egear load之前已经加载了它
DB::enableQueryLog();
$user = User::find(1);
// see the query
$user->load('posts');
$user->load('posts');
$user->loadMissing('posts'); // put it on top to see the difference
dd(DB::getQueryLog());
这就是我认为它的目的
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.