Laravel Eloquent 按关系表列排序

2022-08-30 11:29:02

我试图按表格中的列对表格中的产品进行排序:shop_productspinnedshop_products_options

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

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

}])->paginate(5);

我在商店\产品模型中设置关系:

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

如何解决?


答案 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


编辑:根据@alexw注释 - 如果需要,您仍然可以包含联接表中的列。您可以将它们添加到或调用等。selectaddSelect/selectRaw


答案 2

如果没有手动联接相关表,则无法按相关表列进行排序。Jarek的答案是正确的,但这可能真的很尴尬:

1.第一个问题是你需要担心选择。

->select('products.*')

原因:没有 select() id from shop_products_options 可以选择并水合到产品模型中。

2.第二个问题是你需要担心组By。

->groupBy('products .id');

原因:如果关系为 HasOne,并且产品有多个shop_products_options,则查询将为产品返回更多行。

3.第三个问题是您需要更改所有其他 where 子句:

->where('date', $date)

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

原因:产品和shop_products_options都可以具有“date”属性,在这种情况下,如果不选择带有表“不明确列”的属性,将引发错误。

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


推荐