Laravel Eloquent 禁用自动延迟加载

Net*_*eto 4 laravel eloquent

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)

是否可以禁用此行为?

Lob*_*Baz 6

在您提供的示例中,关系数据是“延迟加载”而不是“急切加载”。这意味着在您首次访问该属性之前,关系数据并未实际加载。

但是,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


dev*_*l Ψ 6

这非常简单,只需添加到您的模型中即可:

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)

正如它所说,它将禁用除生产之外的所有环境的延迟加载。

参考