Laravel – запрос выполняется дважды

Я делаю приложение для планирования свадьбы, где пользователи могут добавлять своих гостей к определенным столам, группам и т. д.

Я пытаюсь составить список всех групп и внутри каждой группы показать каждого гостя в этой группе (на той же странице, что и аккордеон)

Кажется достаточно простым, и это работает, но при использовании DebugBar я вижу, что он делает 2 абсолютно одинаковых запроса, и я не могу понять, почему.

В мероприятии может участвовать множество групп, и в каждой группе может быть много гостей.

$event = Event::find($id_event);
$event->load('group');
$event->group->load([
    "guest" => function ($q) {
       return $q->paginate(10);
    }
]);

Результат:

Редактировать

Забыл упомянуть, что если я добавлю к этому какие-либо другие отношения, они также будут дублировать их.

$event->group->load([
    'guest.plusone',
    "guest" => function ($q) {
       $q->paginate(10);
    }
]);

Редактировать 2

Пытаясь сделать то, что вы предложили, я нашел причину этого, но до сих пор не знаю, почему.

Когда я пытаюсь сделать то, что вы предложили, я получаю тот же результат

$event->load(['group', 'group.guest' => function ($query) {
    $query->paginate(10);
}]);

Но если я удалю обратный вызов для нумерации страниц, я получу только один запрос. Это нормально? Я знаю, что нумерация страниц выполняет один дополнительный запрос, чтобы получить общие результаты, но в данном случае она делает 3 запроса, и 2 из них абсолютно одинаковы.

Прежде всего, попробуйте назвать свои отношения по их типу, например, если в мероприятии много групп, назовите отношение «группы», а не «группа», то же самое для гостей. Во-вторых, можете попробовать $event->load('group.guest'); и посмотреть, какие запросы выполняются. Какие запросы выполняются в этом случае не только без вызова load?

kris gjika 31.07.2024 17:18

@krisgjika На самом деле это приложение уже готово, но было создано одним из наших стажеров, поэтому у него есть множество проблем с производительностью. Я боюсь менять эти отношения, поскольку они могут создать еще больше проблем. Что касается вашей рекомендации, вы можете увидеть изменения выше.

MPN7 31.07.2024 17:43

возможно, вы путаете limit с paginate? зачем вам разбивать модели отношений на страницы?

kris gjika 31.07.2024 18:04

также убедитесь, что вы используете Laravel 11 при использовании ограничений на запросы внутренних отношений, поскольку результат может быть не таким, как вы ожидаете.

kris gjika 31.07.2024 18:05

Нам нужна разбивка на страницы, потому что вы можете иметь неограниченное количество групп. Если мы перечислим 100 групп, в каждой из которых будет по 100 гостей, будет загружено более 1000 гостей. Мы использовали разбиение на страницы, чтобы не выполнять нумерацию страниц вручную. Но я только что проверил с лимитом, и все работает нормально.

MPN7 31.07.2024 18:46

Я попробовал обновиться до laravel 11, но это так же просто: нам нужно переделать всю интеграцию кассовой полосы. Я думаю, что предпочту сделать нумерацию вручную

MPN7 31.07.2024 18:47
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Поиск нового уровня в Laravel с помощью MeiliSearch и Scout
Поиск нового уровня в Laravel с помощью MeiliSearch и Scout
Laravel Scout - это популярный пакет, который предоставляет простой и удобный способ добавить полнотекстовый поиск в ваше приложение Laravel. Он...
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
4
6
60
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

При использовании очереди диспетчеризация не должна выполняться в методах, приводящих к отображению представления, попробуйте использовать ее в методах, не возвращающих представление.

Ответ принят как подходящий

Прежде всего, для того, что вы делаете, результат двух запросов очень ожидаем. См. ниже объяснение:

Объяснение:

$event = Event::query()->find($id_event);
$event->load(['group.guest' => fn ($with) $with->paginate(10)]);

при вызове paginate вы принудительно запускаете запрос, тот же запрос, который был построен на основе определений отношений до этого момента. То же самое произойдет при звонке $with->get(). Но замыкание не ожидает, что вы запустите запрос, и не заботится об этом, а только изменяет запрос, предоставленный внутри. Итак, после того, как запрос выполняется через paginate, обратите внимание, что его результат нигде не используется, замыкание заканчивается, и Laravel запускает запрос на загрузку отношений, как обычно.

Для Ларавел 11:

для того, чего вы хотите достичь, ограничьте количество загруженных моделей отношений до 10 на группу, вам нужно использовать ограничение. Limit не запускает запрос, но изменяет объект запроса, включив в него ограничение при его запуске.

$event = Event::query()->find($id_event);
$event->load(['group.guest' => fn ($with) $with->limit(10)]);

До Laravel 11:

хотя вы можете сделать то же самое в Laravel 10, результат будет другим. Ограничение будет применяться ко всем загруженным гостям, а не к группе. Итак, если у вас есть группы А и Б по 10 гостей в каждой. Полученные данные будут включать 10 гостей группы A и 0 гостей группы B. Это связано с тем, что всего загружено только 10 гостей, а не 10 для каждой группы.

$event = Event::query()->find($id_event);
$event->load(['group.guest' => fn ($with) $with->limit(10)]);

Чтобы добиться той же функциональности, вам необходимо включить https://github.com/staudenmeir/eloquent-eager-limit в свой проект и следовать его инструкциям. (В Laravel 11 этот пакет был объединен)

Другие вопросы по теме