Laravel Eloquent Trier par relation table colonne
J'ai essayé de trier les produits de shop_products
table par pinned
colonne de shop_products_options
table:
$products = ShopProduct::with(['options' => function ($query) {
$query->orderBy('pinned', 'desc');
}])->paginate(5);
J'ai défini la relation dans la boutiquemodèle de produit:
public function options()
{
return $this->hasOne('ShopOptions');
}
Mais les produits ne sont pas triés. Je reçois une requête qui ne fonctionne qu'avec shop_products_options
table.
SELECT * FROM `shop_products_options` WHERE `shop_products_options`.`product_id` in ('8', '9', '10', '11', '12') ORDER BY `pinned` DESC
Comment le réparer?
2 réponses
Le chargement impatient utilise des requêtes séparées, vous devez donc vous joindre à ceci:
$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
la clause est là pour ne pas ajouter de colonnes jointes à votre modèle Product
.
Edit: selon le commentaire @ alexw - vous pouvez toujours inclure des colonnes de tables jointes si vous en avez besoin. Vous pouvez les ajouter à select
ou appeler addSelect/selectRaw
etc.
Vous ne pouvez pas Trier par colonne de table associée sans joindre manuellement la table associée. La réponse de Jarek est correcte mais cela pourrait être vraiment gênant:
1.Le premier problème est que vous devez vous soucier de select.
->select('products.*')
Raison: sans select () id de shop_products_options peut être sélectionné et hydraté dans le modèle de produit.
2.Le deuxième problème est que vous devez vous soucier de groupBy.
->groupBy('products .id');
Raison: si la relation est HasOne et qu'il y en a plusieurs shop_products_options pour le produit, la requête retournera plus de lignes pour les produits.
3.Le troisième problème est que vous devez changer toutes les autres clauses where de:
->where('date', $date)
À
->where('products .date', $date)
Raison: products et shop_products_options peuvent tous deux avoir l'attribut" date "et dans ce cas sans sélectionner l'attribut avec la table" ambigu column " erreur sera levée.
4.Le quatrième problème est que vous utilisez des noms de table(pas des modèles) et c'est aussi mauvais et maladroit.
->where('products.date', $date)
5.Le cinquième problème est que vous devez vous soucier des suppressions douces pour les tables jointes. Si shop_products_options utilise le trait SoftDeletes, vous devez ajouter:
->where('shop_products_options .deleted_at', '=', null)
Tous les problèmes ci-dessus sont très frustrants et joindre des tables avec eloquent peut introduire dans votre code de nombreux problèmes. J'ai créé un paquet qui prend soin de tous les problèmes ci-dessus et vous pouvez trier par attribut de relation avec une manière élégante, pour votre cas ce serait:
$products = Shop\Product::orderByJoin('options.pinned', 'desc')->paginate(5);
Pour plus d'informations voir https://github.com/fico7489/laravel-eloquent-join