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?

28
demandé sur alexk 2014-05-08 03:15:00

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.

64
répondu Jarek Tkaczyk 2016-06-20 03:43:32

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

8
répondu fico7489 2017-12-17 19:08:34