У меня следующие три таблицы:
A ------------- | id | name | ------------- B -------------------- | id | A_id | name | -------------------- C -------------------- | id | B_id | name | --------------------
Таким образом, данные в таблице C
относятся к данным в таблице B
которые относятся к данным в таблице A
Теперь я хочу запросить C
, а также получить данные из B
и A
и следующий код делает трюк просто прекрасным.
C::with('B.A')->get();
Проблема в том, что я хочу запросить C
с некоторыми ограничениями. Одним из этих ограничений является id
A
Я пробовал следующее:
C::with(array('BA' => function ($query) { $query->where('id', '=', $constraint); }))->get();
Но кажется, что Eloquent будет извлекать все строки в C
даже не принимая во внимание ограничение, за исключением случаев, когда он выполняет запрос для извлечения данных в таблице A
Как мне обойти эту проблему? Нужно ли мне добавить другое поле в C
, то есть A_id
, и сопоставить $constraint
с этим полем?
Вы смешиваете метод with()
с JOIN
SQL, и это происходит очень часто.
Когда вы используете Foo::with('bar')->where_something(1)
, Laravel сначала загрузит Foo
а затем, основываясь на Foo.bar_id
, он загрузит Bar
. Он служит для того, чтобы рассказывать Laravel о желаемых зависимостях загрузки вашей модели от комбинированного запроса, что значительно улучшает производительность итераций на этих моделях.
Если вы его не используете, должны быть выполнены следующие запросы:
SELECT * FROM foos WHERE foos.something = 1; SELECT * FROM bars WHERE bars.id = 30; SELECT * FROM bars WHERE bars.id = 57; SELECT * FROM bars WHERE bars.id = 134; SELECT * FROM bars WHERE bars.id = 1096;
Если вы используете его, с другой стороны:
SELECT * FROM foos WHERE foos.something = 1; SELECT * FROM bars WHERE bars.id IN (30, 57, 134, 1096); // Eager loading
Когда вы добавляете условие к этому with()
, вы ограничиваете только загрузку этих зависимостей, а не первый запрос.
Чтобы достичь того, чего вы хотите, вам нужно использовать ->join()
.
C::with(array('b', 'b.a')) ->join('b', 'b.id', '=', 'c.b_id') ->join('a', 'a.id', '=', 'b.a_id') ->where('a.id', '=', $ID) ->get('c.*');
Я включил параметр with()
, потому что не знал, нужно ли вам получить доступ к $c->b->a
. Если вы этого не сделаете, и вам просто нужны данные $c
, вы можете удалить параметр with()
поскольку он будет запрашивать для B и A без необходимости.