我有这个结构:
学校 - > hasMany - >类
因此,当我通过artisan tinker
App\School::with('schoolclasses')->find(2283)->schoolclasses;
我可以毫无问题地获得课程。
但是当我尝试没有使用时,我仍然可以毫无问题地获得相同的结果:
App\School::find(2283)->schoolclasses;
默认情况下Eloquent
是否会加载?如果是,如何禁用它?
答案 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
然后你只得到课程。
第二个直接获得这些课程。结果是一样的,因为你要求的是相同的记录。
如果您不想获得热切的加载结果,那么就不要查询它们。