猿问

如何使用 Eloquent 重构此代码以缓解 N+1 查询问题?

我想了解在这种特殊情况下,是否有一种有效的方法可以使用 Eloquent 来缓解 N+1 查询问题。背景是我目前正在使用 Laravel 8 构建一个 API。


概括

就本题而言,示例是Store-> has much -> Orders-> Many-to-many -> Products,即:一个商店有很多订单,一个订单有很多产品,但一个产品可以属于很多不同的商店。有一个product_orders数据透视表,它还跟踪一些附加值,例如unit_price等quantity。


我的目标是创建一个 API 端点,其中列出了商店的所有订单以及该特定订单上的产品。


{

    "data": [

        {

            "id": "6531a4d4-b066-4673-ad59-8b4a49c0d675",

            "object": "order",

            "comments": "Sequi perspiciatis quasi dolorum rerum. Rem dolore nihil sint magnam totam explicabo. Non officia est ut inventore modi.",

            "order_items": [

                {

                    "product_id": "3c6400f5-fde9-47cb-ad05-ef164e00583e",

                    "product_name": "omnis inventore",

                    "unit_price": "17.15",

                    "quantity": 8

                },

                {

                    "product_id": "c208c8dd-df71-4331-909d-0615ec763555",

                    "product_name": "accusantium omnis",

                    "unit_price": "81.88",

                    "quantity": 3

                },

                {

                    "product_id": "05129518-882b-4558-b68f-df06c804a6d3",

                    "product_name": "voluptatem vitae",

                    "unit_price": "52.58",

                    "quantity": 4

                },

            ],

            "supplier_invoice_no": ABC1234,

        }

    ],

    }

}

对于此任务,我利用 Eloquent API 资源,因此我的代码如下:


路线/api.php

Route::apiResource('/stores/{store}/orders', 'Api\Stores\StoreOrderController');

StoreOrderController.php

我正在Store使用路由模型绑定检索模型。


public function index(Store $store)

    {

        return StoreOrdersResource::collection($store->orders);

    }

商店订单资源.php

这个 API 资源将 JSON 响应过滤为仅相关数据,我相信这就是我的问题所在。对于Order通过此的每一个StoreOrdersResource,我都会检索$this->productsaka $order->products,因此会进行重复的查询,为商店的每一个订单查询订单的产品。

慕容森
浏览 87回答 1
1回答

凤凰求蛊

为了避免额外的查询,您可以在控制器中加载关系。就像是// Models/Order.phppublic function items(){    return $this->belongsToMany(Product::class)                ->withPivot('unit_price', 'quantity');}// StoreOrderController.phppublic function index(Store $store){    $store->load('orders.items');    return StoreOrdersResource::collection($store->orders);}// StoreOrdersResource.phppublic function toArray($request){    return [        // ...        'order_items' => $this->items,    ];}
随时随地看视频慕课网APP
我要回答