У меня есть две модели: Box и BoxLocations. Box имеет hasMany отношение к BoxLocations, а BoxLocations имеет belongsTo отношение к Box.
BoxLocations также имеет атрибут, который добавляется к модели, требующей одной части информации из отношения Box.
Я заметил, что при вызове Box::with(['BoxLocations']->)all(); я вижу, что модель BoxLocations перезагружает отношение Box. Это происходит для каждого BoxLocation (50 с лишним раз)
Разве laravel не отслеживает, что Box уже был загружен из первоначального запроса Box::with(['BoxLocations']->)all();, а затем передает это в отношение BelongsTo?
Я пытаюсь оптимизировать веб-систему, и когда загруженный атрибут загружается (досадно, что он требуется каждый раз, когда он также загружается), он вызывает 50 нечетных обращений к базе данных для той же модели Box, которую он уже загрузил.
Если laravel этого не делает - есть ли лучший способ добиться этого?






Laravel использует нетерпеливая загрузка, когда вы используете метод with().
When accessing Eloquent relationships as properties, the relationship data is "lazy loaded". This means the relationship data is not actually loaded until you first access the property. However, Eloquent can "eager load" relationships at the time you query the parent model. Eager loading alleviates the N + 1 query problem.
Итак, если вы сделаете это:
$boxes = Box::with('BoxLocations')->get();
Он уже загрузит отношения, но, скажем, вы сделаете это:
$boxes = Box::all();
foreach($boxes as $box)
{
echo box->boxlocation->name;
}
Если у вас есть 50 ящиков, этот цикл будет выполнять 51 запрос.
Но когда вы используете метод with и загружаете отношение, этот цикл будет выполнять только 2 запроса.
Вы также можете использовать Ленивая нетерпеливая загрузка и решить, когда вы хотите загрузить отношения
Спасибо, не могли бы вы сказать мне, сколько запросов выполнялось с использованием отношений? это может быть ошибка, и мы могли бы сообщить об этом. Кроме того, я был бы признателен, если бы вы показали запрос, который вы сделали
Я не могу сейчас вспомнить код, но в основном у меня была таблица производителей, скажем, «Apple», и таблица устройств с множеством продуктов Apple. При выполнении Devices::with('manufacturers')->get() вы получаете один запрос для каждого производителя устройств. Я думаю, что он должен получить производителя для первого, а затем кэшировать его для остальных. Однако это в устаревшем коде laravel 5.5 ... так что сейчас это может не быть проблемой.
Я отметил этот ответ как правильный; однако я обнаружил, что laravel по-прежнему выполняет больше запросов, чем мне нужно, с помощью этого метода. Я обнаружил, что гораздо лучше написать запрос к БД, чтобы получить поля, которые я хотел, в одном вызове БД, а не позволять отношениям laravels обращаться к базе данных несколько раз.