shop_products
テーブルのpinned
列でshop_products_options
テーブルの製品をソートしようとしました:
$products = Shop\Product::with(['options' => function ($query) {
$query->orderBy('pinned', 'desc');
}])->paginate(5);
Shop\Productモデルでリレーションを設定します。
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
修正方法
積極的な読み込みでは個別のクエリが使用されるため、このために参加する必要があります。
$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コメントごと-必要に応じて、結合テーブルの列を含めることができます。それらをselect
に追加するか、addSelect/selectRaw
などを呼び出すことができます。
関連テーブルを手動で結合しないと、関連テーブルの列で並べ替えることはできません。 Jarekの答えは正しいが、これは本当に厄介かもしれない。
1.最初の問題は、選択について心配する必要があるということです。
->select('products.*')
理由:select()なしで、shop_products_optionsのidを選択して、製品モデルにハイドレートできます。
2. 2番目の問題は、groupByについて心配する必要があることです。
->groupBy('products .id');
理由:リレーションがHasOneで、製品に複数のshop_products_optionsがある場合、クエリは製品の行をさらに返します。
3. 3番目の問題は、他のすべてのwhere句を変更する必要があることです:
->where('date', $date)
に
->where('products .date', $date)
理由:製品とshop_products_optionsは両方とも「日付」属性を持つことができ、その場合、テーブルで属性を選択しないと「あいまいな列」エラーがスローされます。
4. 4番目の問題は、(モデルではなく)テーブル名を使用していることであり、これもまた悪くて厄介です。
->where('products.date', $date)
5. 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 を参照してください