Laravel Eloquent按关系表列排序

Sac*_*cha 31 php orm laravel eloquent

我试图从shop_products表中逐pinned列对产品进行排序shop_products_options:

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

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

}])->paginate(5);
Run Code Online (Sandbox Code Playgroud)

我在Shop\Product模型中设置关系:

public function options()
{
    return $this->hasOne('Shop\Options');
}
Run Code Online (Sandbox Code Playgroud)

但产品没有分类.我得到一个只适用于shop_products_options表的查询.

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

怎么解决?

Jar*_*zyk 69

预先加载使用单独的查询,因此您需要为此加入:

$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);
Run Code Online (Sandbox Code Playgroud)

SELECT子句是为了不将连接列附加到Product模型中.


编辑:根据@alexw注释 - 如果需要,您仍然可以包含已连接表中的列.您可以将它们添加到select或拨打addSelect/selectRaw等.


fic*_*489 10

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

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

->select('products.*')
Run Code Online (Sandbox Code Playgroud)

原因:没有来自shop_products_options的select()id可以选择并水合成Product model.

2.第二个问题是你需要担心groupBy.

->groupBy('products .id');
Run Code Online (Sandbox Code Playgroud)

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

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

->where('date', $date)
Run Code Online (Sandbox Code Playgroud)

->where('products .date', $date)
Run Code Online (Sandbox Code Playgroud)

原因:product和shop_products_options都可以具有"date"属性,在这种情况下,不会选择带有"ambiguous column"错误的属性,将会抛出错误.

4.第四个问题是你使用的是表名(不是模型),这也很糟糕而且很尴尬.

->where('products.date', $date)
Run Code Online (Sandbox Code Playgroud)

5.第五个问题是你需要担心连接表的软删除.如果shop_products_options使用SoftDeletes特征,则必须添加:

->where('shop_products_options .deleted_at', '=', null)
Run Code Online (Sandbox Code Playgroud)

以上所有问题都非常令人沮丧,加入雄辩的表可能会给你的代码带来许多问题.我创建了一个解决上述所有问题的包,你可以通过关系属性和优雅的方式进行排序,对于你的情况,它将是:

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

有关详细信息,请参阅https://github.com/fico7489/laravel-eloquent-join


Ram*_*ira 5

+6 Laravel 版本还有另一种使用子查询排序的方法:

$products = Shop\Product::orderByDesc(
        Shop\Options::select('pinned')
            ->whereColumn('product_id', 'shop_products.id')
            ->orderByDesc('pinned')
            ->limit(1)
)->paginate(5);
Run Code Online (Sandbox Code Playgroud)