I am currently running on Laravel 5.1.19 and am observing the following issue:
Assume the following models (Students and Teachers as example):
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);
}
}
If you then query an instance of Teacher
and (lazy) eager load its Student
s, the ->rel_teacher
magic member of all students triggers a fresh query against that 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>";
Query log for the above code:
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 ...
The issue: Eloquent has an instance of Teacher
#1 when find(1)
finishes. I expect eloquent to pass a reference to this very PHP-Objet to the eager loaded Student
s so that $student->teacher
returns that reference instead of triggering another query.
another, negative sideffect: even if the queries were no performance issue (which they are!) i'd have hundrets of instances for Teacher
#1 fyling around and that is very contrary to the unit-of-work pattern.
Question: What can i do to make eloquent behave as i expect it to? if not possible: which of the PHP-ORMs are "intelligent" enough and do this simple trick?
UPDATE 1: I did try to remove the underscore from the relation name - same result.
UPDATE 2: As mentioned in an answer, with
/load
with both relations does a almost-perfect job: $teacher->load('rel_students.rel_teacher')
.
This reduces the queries for the teacher to 2, but that still leaves the issue that $student->rel_teacher !== $teacher
. This is fine until someone modifies either object and then it starts getting hairy.