Laravel возвращает коллекцию с дубликатами первой модели - PullRequest
0 голосов
/ 07 декабря 2018

Я занимаюсь разработкой приложения Laravel 5.7 (API) с базой данных PostgreSQL.Соответствующие модели: User (клиенты и сотрудники), Car и Request.

сотрудник User создает Request для Car, который принадлежит клиенту User.

Отношения:

  • Car (как клиент ) : User = n:m
  • Car : Request = 1:n
  • User : Request (как сотрудник ) = 1:n

enter image description here

(Дизайн данныхсубоптимальный, мягко говоря, но в любом случае, это настоящая реальность.)

Теперь к актуальной проблеме.Я хочу отобразить все Request с клиента User:

Request::query()
    ->join('user_car', 'user_car.car_id', '=', 'request.car_id')
    ->join('user', 'user.id', '=', 'user_car.user_id')
    ->where('user.id', '=', $customer->id)
    ->select()
    ->get();

клиента с указанным $customer->id имеет n Request s.И длина результата Collection указанного выше вызова верна.Но все эти n записи являются дубликатами первого.Означает: я получаю список с n экземплярами Request#1.

Почему первый вызов возвращает список ссылок на один и тот же Model объект? Это так?(известная) ошибка?


ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ

Отношения:

class User extends \Illuminate\Foundation\Auth\User
{
    // ...
    public function cars()
    {
        return $this->belongsToMany('App\Car', 'user_car')->withTimestamps();
    }
    public function requests()
    {
        return $this->hasMany(Request::class, 'user_id');
    }
}

class Car extends Model
{
    // ...
    public function users()
    {
        return $this->belongsToMany('App\User', 'user_car')->withTimestamps();
    }
    public function requests()
    {
        return $this->hasMany(Request::class);
    }
}

class Request extends Model
{
    // ...
    public function car()
    {
        return $this->belongsTo(Car::class);
    }
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

запрос правильный.

Я зарегистрировал запросы к базе данных, получил сгенерированный оператор

SELECT *
FROM "request"
INNER JOIN "user_car" ON "user_car"."car_id" = "request"."car_id"
INNER JOIN "user" ON "user"."id" = "user_car"."user_id"
WHERE "user"."id" = 1;

... и выполнил его вручную.Таблица результатов содержит, как и ожидалось, n различные записи.

НЕ просто ссылки

Результирующие Collection записи экземпляров ссылок наразличные объекты:

$test1 = $resultCollection->first();
$test2 = $resultCollection->last();
$test3 = spl_object_hash($test1);
$test4 = spl_object_hash($test2);

Вывод Xdebug:

$test3 = "0000000077505ccd000000007964e0a8" <-- ccd0
$test4 = "0000000077505c33000000007964e0a8" <-- c330

Обходной путь

Я нашел обходной путь.Этот вызов

Request::whereIn('car_id', $customer->cars()->pluck('id')->toArray())->get();

... возвращает правильный / ожидаемый набор моделей.

1 Ответ

0 голосов
/ 07 декабря 2018

Во-первых, обратите внимание, что ваши хеши объектов на самом деле не идентичны, и вы, вероятно, имеете дело с двумя отдельными экземплярами.

Вероятно, возникла проблема с неоднозначными именами столбцов .Когда вы JOIN объединяете несколько таблиц, любые совпадающие / дублирующие имена столбцов будут содержать значение последнего соответствующего столбца.Ваш SQL GUI / клиент обычно разделяет их.К сожалению, Laravel не имеет механизма префикса и просто использует ассоциативный массив.

Если все ваши таблицы имеют столбец первичного ключа id, каждый объект Request в вашем наборе результатов, скорее всего, будет иметьтот же идентификатор - идентификатор пользователя, который вы передаете в условии WHERE.

Вы можете исправить это в существующем запросе, явно выбрав столбцы, необходимые для предотвращения неоднозначности.Используйте ->select(['request.*']), чтобы ограничить возвращаемую информацию данными объекта Request.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...