编程语言
首页 > 编程语言> > php – Laravel Eloquent渴望加载:孩子们缺少父参考(排序N 1)

php – Laravel Eloquent渴望加载:孩子们缺少父参考(排序N 1)

作者:互联网

我目前正在Laravel 5.1.19上运行,并且正在观察以下问题:

假设以下模型(学生和教师为例):

class Teacher extends \Illuminate\Database\Eloquent\Model {
    public function rel_students() {
        return $this->hasMany(Student::class);
    }
}

class Student extends \Illuminate\Database\Eloquent\Model {
    public function rel_teacher() {
        return $this->belongsTo(Teacher::class);
    }
}

如果您随后查询教师实例并且(懒惰)急切加载其学生,则所有学生的 – > rel_teacher魔术成员会触发针对该教师的新查询:

$teacher = Teacher::with('rel_students')->find(1);
// or this, the effect is the same
$teacher = Teacher::find(1); $teacher->load('rel_students');

foreach ($teacher->rel_students as $student)
    echo $student->teacher->name . "<br>";

查询以上代码的日志:

SELECT * FROM teachers WHERE id = 1
SELECT * FROM students WHERE teacher_id IN (1)
SELECT * FROM teachers WHERE id = 1
SELECT * FROM teachers WHERE id = 1 # what is going on here?!
SELECT * FROM teachers WHERE id = 1
... and so forth for every student ...

问题:当find(1)结束时,Eloquent有一个教师#1的实例.我希望雄辩能够将对这个PHP-Objet的引用传递给渴望加载的学生,以便$student->老师返回该引用而不是触发另一个查询.

另一个消极的副作用:即使查询没有性能问题(他们是!),我会为教师#1翻译实例,这与工作单元模式非常相反.

问题:我能做些什么才能像我期望的那样表现出雄辩的表现?如果不可能:哪个PHP-ORM足够“智能”并做这个简单的技巧?

更新1:我确实尝试从关系名称中删除下划线 – 相同的结果.

更新2:正如在答案中所提到的,使用/ load两个关系做了几乎完美的工作:$teacher-> load(‘rel_students.rel_teacher’).
这会将对教师的查询减少到2,但仍然存在$student-> rel_teacher!== $teacher的问题.这是好的,直到有人修改任何一个对象,然后它开始变得毛茸茸.

解决方法:

如果你想从学生中引用老师,你需要为每个学生延迟加载它们(‘rel_students.rel_teacher’)然后回显$student-> rel_teacher->名称或使用你正在循环的教师模型关于echo $teacher->名称

编辑

$teacher = Teacher::with('rel_students.rel_teacher')->find(1);

foreach($teacher->rel_students as $student)
{
    if($teacher->id != $student->rel_teacher->id)
    {
        dd('error');
    }
    echo $student->rel_teacher->name . "<br>";
}

标签:php,eloquent,eager-loading
来源: https://codeday.me/bug/20190702/1357115.html