Подтвердить что ты не робот

Laravel Eloquent сортировать по столбцу таблицы отношений

Я пытался сортировать продукты из таблицы shop_products столбцом pinned из таблицы shop_products_options:

$products = Shop\Product::with(['options' => function ($query) {

    $query->orderBy('pinned', 'desc'); 

}])->paginate(5);

Я установил отношение в Shop\Product model:

public function options()
{
    return $this->hasOne('Shop\Options');
}

Но продукты не сортируются. Я получаю запрос, который работает только с таблицей shop_products_options.

SELECT * FROM `shop_products_options` WHERE `shop_products_options`.`product_id` in ('8', '9', '10', '11', '12') ORDER BY `pinned` DESC

Как это исправить?

4b9b3361

Ответ 1

В режиме ожидания для загрузки используются отдельные запросы, поэтому для этого требуется объединение:

$products = Shop\Product::join('shop_products_options as po', 'po.product_id', '=', 'products.id')
   ->orderBy('po.pinned', 'desc')
   ->select('products.*')       // just to avoid fetching anything from joined table
   ->with('options')         // if you need options data anyway
   ->paginate(5);

SELECT существует, чтобы не добавлять объединенные столбцы к вашей модели Product.


edit: согласно комментарию @alexw - вы все равно можете включать столбцы из объединенных таблиц, если они вам понадобятся. Вы можете добавить их в SELECT или вызвать addSelect/selectRaw и т.д.

Ответ 2

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

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

->select('products.*')

причина: без select() id из shop_products_options может быть выбран и гидратирован в модель продукта.

2. Вторая проблема заключается в том, что вам нужно беспокоиться о groupBy.

->groupBy('products .id');

причина: если отношение HasOne и для продукта более одного shop_products_options, запрос возвращает больше строк для продуктов.

3. Третья проблема заключается в том, что вам нужно изменить все остальные предложения where:

->where('date', $date)

к

->where('products .date', $date)

причина: продукты и shop_products_options могут иметь атрибут "дата", и в этом случае без выбора атрибута с ошибкой таблицы "неоднозначный столбец" будет выведено.

4. Четвертая проблема заключается в том, что вы используете имена таблиц (а не модели), и это также плохо и неудобно.

->where('products.date', $date)

5. Пятая проблема заключается в том, что вам нужно беспокоиться о мягких ударах для объединенных таблиц. Если shop_products_options использует свойство SoftDeletes, вы должны добавить:

->where('shop_products_options .deleted_at', '=', null)

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

$products = Shop\Product::orderByJoin('options.pinned', 'desc')->paginate(5);

Подробнее см. https://github.com/fico7489/laravel-eloquent-join