Предотвратить запрос к БД, если отношение не было загружено

У меня есть 2 модели, например, Country и City с отношениями one-to-many.

Когда я запускаю этот код

$countries = Country::query()->with('cities')->get();

foreach ($countries as $country) {
    $cities = $country->cities;

    foreach ($cities as $city) {
        dump($city->country);
    }
}

, при каждом вызове $city->country у меня есть запрос к БД

select * from `countries` where `countries`.`id` = ? limit 1 

Если отношение (в моем случае cities.country) не загружалось с жадной загрузкой, есть ли возможность предотвратить выполнение запроса к БД при каждом вызове $city->county?

Мне не нужна переменная $country. Мне нужно получить null, если отношение cities.country не было загружено в основном запросе.

зачем вам делать $city->country ? У вас уже есть объект страны прямо здесь....

Wouter Van Damme 28.05.2019 16:33

@WouterVanDamme это просто для примера. Мне нужно получить null, когда я звоню $city->country в моем случае

Yuriy L. 28.05.2019 16:37

Это не то, как работает laravel. Если вы попытаетесь вызвать отношение, которое не загружено, оно его загрузит. Как устроен ваш код, никогда не будет случая, когда $city->country вернет null. Если вы запросили City напрямую и зациклили результаты, они могут быть, но вы запрашиваете Country, а затем зациклили, так что этого никогда не будет.

Tim Lewis 28.05.2019 16:39

@ТимЛьюис, спасибо

Yuriy L. 28.05.2019 16:41

Я не понимаю, почему мой вопрос был заминусован. Это мой случай, и мне нужно решить его внутри моего Mapper и HttpResource. Это понижение является предвзятым.

Yuriy L. 28.05.2019 16: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-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
0
5
81
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Почему бы тогда не сделать обратное:

$cities = City::with('country')->get();

// this way you would loop only once:

foreach ($cities as $city) {
    dump($city->country);
}

Используя ваш подход, тогда это:

foreach ($countries as $country) {
    $cities = $country->cities;

    foreach ($cities as $city) {
        dump($country);
        // here the $country variable 
       // is the same as the $city->country one, so no need to query it again..
    }
}

Спасибо, но мне не нужно обратное, мне нужно прекратить вложенность отношений.

Yuriy L. 28.05.2019 16:31

Вы хотите древовидную структуру? github.com/lazychaser/laravel-nestedset#installation

Ahmed Aboud 28.05.2019 16:33

Тогда вы можете использовать мое редактирование.. не нужно вызывать $city->country, когда в этом цикле $country — это то, что у вас уже есть.. так зачем запрашивать его снова?

nakov 28.05.2019 16:34

Мне не нужна переменная $country. Мне нужно прекратить отношения вложенности, поэтому мне нужно null при вызове dump($city->county)

Yuriy L. 28.05.2019 16:35

Не могли бы вы посмотреть на свой вопрос и изменить его на то, что вам нужно, потому что из того, что вы сейчас спрашиваете, это ответ.

nakov 28.05.2019 16:37

переопределите city в вашей модели и явно поставьте return null;, потому что ваш вариант использования вообще не имеет смысла :) Если вам нужно вернуть null, просто поставьте null и все.

nakov 28.05.2019 16:39
Ответ принят как подходящий

Благодаря

https://laracasts.com/discuss/channels/laravel/how-to-check-if-an-relationship-has-been-eager-loaded-or-not

В моем случае

//...
if ($city->relationLoaded('country')) {
    dump($city->country);
} else {
    dump(null);
}
//...

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

nakov 28.05.2019 18:03

@nakov Если я хочу получить не нулевое, а значение $country, я должен установить запрос with как with('cities.country'). Итак, с этой проверкой (relationLoaded) у меня больше контроля над запросами к БД, основная цель достигнута.

Yuriy L. 28.05.2019 18:06

Я хочу сказать, что это $city->relationLoaded('country') никогда не вернется, потому что вы никогда не стремитесь загрузить страну из города, как вы упомянули в своем комментарии. Так что не вижу смысла в проверке вообще. Но вы лучше знаете свое дело, так что продолжайте, дискуссия все равно ни к чему не приведет :)

nakov 28.05.2019 18:11

Это несправедливо, чем этот ответ был отклонен. Человек, который это сделал, не понял предмета. Может ли этот человек объяснить здесь, почему за него проголосовали?

Yuriy L. 28.05.2019 19:25

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