Laravel 5:默认情况下Eloquent急切加载吗?

时间:2016-01-06 05:24:04

标签: php laravel laravel-5.1

我有这个结构:

学校 - > hasMany - >类

因此,当我通过artisan tinker

尝试以下代码时
App\School::with('schoolclasses')->find(2283)->schoolclasses;

我可以毫无问题地获得课程。

但是当我尝试没有使用时,我仍然可以毫无问题地获得相同的结果:

App\School::find(2283)->schoolclasses;

默认情况下Eloquent是否会加载?如果是,如何禁用它?

2 个答案:

答案 0 :(得分:5)

不,Laravel默认情况下并不急于加载。让我们一步一步来。让我们暂时忽略->schoolclasses;

App\School::with('schoolclasses')->find(2283);

这将查询数据库两次。首先,它将获得主键为2283的School。然后,它将立即查询数据库并获取所有相关的schoolclasses

App\School::find(2283);

这只会查询数据库一次。它只会获得School。到目前为止还没有急切的加载。如果您调试并跟踪数据库查询,您将看到这只会查询数据库一次,而急切加载将查询它两次。

当您尝试通过执行schoolclasses访问->schoolclasses;时,一切正常。那你为什么得到同样的结果呢?它有点欺骗性,但它不一样。当您尝试访问schoolclasses时,Laravel将检查它是否已被急切加载。如果是这样,它将返回schoolclasses的集合。没有查询。它只是立即返回它们。但是,如果您没有急于加载它们,Laravel将在现场查询数据库并获取schoolclasses。最终,对于这个特定的例子,你会得到相同的结果,但是当你查询数据库时会有所不同。

然而,这实际上是热切加载的主要好处的一个不好的例子。

急切加载的主要好处是缓解N + 1查询问题。假设您想要获得5所学校及其所有课程。如果没有急切的加载,这就是你要做的:

$schools = School::take(5)->get();

foreach ($schools as $school)
{
    $schoolclasses = $school->schoolclasses;
}

对于这样一个简单的任务,总共有6个查询。我在下面添加了评论,以了解查询的来源:

$schools = School::take(5)->get(); // First query

foreach ($schools as $school)
{
    // For each school, you are querying the database again to get its related classes.
    // 5 schools = 5 more queries
    $schoolclasses = $school->schoolclasses;
}

但是,如果您急切地加载所有内容,则只有两个查询:

// Two queries here that fetches everything
$schools = School::with('schoolclasses')->take(5)->get();

foreach ($schools as $school)
{
    // No more queries are done to get the classes because
    // they have already been eager loaded
    $schoolclasses = $school->schoolclasses;
}

答案 1 :(得分:0)

你写了两次。第一个请求获取学校,类似于:

学校:

class - class - class

然后你只得到课程。

第二个直接获得这些课程。结果是一样的,因为你要求的是相同的记录。

如果您不想获得热切的加载结果,那么就不要查询它们。