Laravel: Eager loading может выполнить запрос не туда

Когда вы работаете с несколькими базами данных в Laravel, есть один довольно хитрый подвох при использовании жадной загрузки (eager loading) и он легко может сбить вас с толку.

Представьте, что в вашем приложении есть две модели:

  • Order - хранится в внешней базе данных;

  • Customer - живёт в основной (дефолтной) базе данных.

Примерно так:

class Order extends Model
{
    protected $connection = 'external';

    public function customer(): BelongsTo
    {
        return $this->belongsTo(Customer::class);
    }
}

class Customer extends Model
{
    // использует базу по умолчанию
}

Вы могли бы логично ожидать, что при выполнении запроса:

Order::with('customer')->get();

Laravel получит заказы из внешней базы данных (external) и отдельно клиентов из основной (mysql), как указано в настройках. Но на практике это не работает так, как кажется.

Фреймворк пытается найти таблицу customers в той же базе данных, что и заказы, то есть в external. Это приведёт к ошибке, потому что таблицы там просто нет.

Почему так происходит

В Laravel при eager loading создаётся новый экземпляр модели, на который затем накладываются ограничения для связи. Но если связанная модель не имеет явного свойства $connection, то Laravel автоматически унаследует соединение родителя.

А это означает, что связь customer будет искать customers в той же базе данных, что и orders, то есть в external, хотя мы хотим, чтобы она использовала дефолтную базу.

Как исправить

Решение простое: всегда указывайте свойство $connection даже для модели, которая должна использовать стандартное соединение. Так Laravel не будет приписывать ей внешний connection от родителя.

В итоге модель Customer должна выглядеть так:

class Customer extends Model
{
    protected $connection = 'mysql';
}

Теперь запрос Order::with('customer')->get() будет работать корректно: заказы получаются из external, а данные клиентов из mysql.

Похожие статьи

Рекомендательные технологии Подробнее
Разработка и инструменты 6 месяцев назад

Как загружать большие файлы в Laravel

Подробный практический гайд по загрузке больших файлов в Laravel с использованием разбиения на части и функцией возобновления. Объясняется, как организовать сервер и клиент для надёжной загрузки больших файлов.

Разработка и инструменты 6 месяцев назад

Условные операторы if else в Bash и shell-скриптах

Использование условных операторов if, else и elif в shell-скриптах Bash. Рассматриваются базовый синтаксис, числовые и строковые сравнения, проверки файлов, вложенные условия и практические примеры для повседневных задач администрирования и автоматизации.

Laravel получил встроенную поддержку Passkeys

Laravel получил встроенную поддержку passkeys через пакет laravel/passkeys. Новая реализация упрощает passwordless-аутентификацию на базе WebAuthn и поддерживает биометрию, аппаратные ключи и интеграцию с Fortify.

Разработка и инструменты 6 месяцев назад

Декодирование JSON из HTTP-ответов в Laravel

Как Laravel обрабатываются JSON-ответы HTTP-клиента и какие возможности дают флаги декодирования JSON. Рассматриваются ошибки декодирования, работа с большими числами и настройка флагов по умолчанию.