Laravel 默认情况下具有自动急切加载功能,这可能会导致一些多重查询问题,例如:
// If do something like this
$posts = Post::published()->get();
// then
foreach ($posts as $p) {
echo $p->author->name;
}
// Eloquent will query the author for every post
Run Code Online (Sandbox Code Playgroud)
是否可以禁用此行为?
在您提供的示例中,关系数据是“延迟加载”而不是“急切加载”。这意味着在您首次访问该属性之前,关系数据并未实际加载。
但是,Eloquent 可以在查询父模型时“预加载”关系。预加载缓解了 N+1 查询问题。
要预先加载关系,您可以使用 eloquentwith()方法:
$posts = Post::published()->with('author')->get();
Run Code Online (Sandbox Code Playgroud)
现在每个都post将立即加载模型author,从而避免了 N + 1 问题。
您还可以指定是否只想立即加载特定列:
$posts = Post::published()->with('author:id,name')->get();
Run Code Online (Sandbox Code Playgroud)
如果您希望在检索模型时始终加载关系,您可以在模型上定义 $with 属性:
class Post extends Model
{
/**
* The relationships that should always be loaded.
*
* @var array
*/
protected $with = ['author'];
/**
* Get the author that wrote the book.
*/
public function author()
{
return $this->belongsTo('App\Author');
}
}
Run Code Online (Sandbox Code Playgroud)
更多信息:https://laravel.com/docs/6.x/eloquent-relationships#eager-loading
这非常简单,只需添加到您的模型中即可:
public $preventsLazyLoading = true;
然后,如果您尝试延迟加载关系,您将收到错误
Illuminate\Database\LazyLoadingViolationException : Attempted to lazy load [<ModelName>] on model [<ModelName>] but lazy loading is disabled.
Run Code Online (Sandbox Code Playgroud)
您还可以为模型创建一个父类,例如
abstract class Model extends \Illuminate\Database\Eloquent\Model
{
public $preventsLazyLoading = true;
}
Run Code Online (Sandbox Code Playgroud)
然后在您的模型中扩展它,它们将自动禁用延迟加载。
适用于 Laravel 8 或更高版本
还有另一种方法可以在应用程序服务提供中禁用它
// app/Providers/AppServiceProvider.php
public function boot()
{
Model::preventLazyLoading(! app()->isProduction());
}
Run Code Online (Sandbox Code Playgroud)
正如它所说,它将禁用除生产之外的所有环境的延迟加载。
| 归档时间: |
|
| 查看次数: |
9630 次 |
| 最近记录: |