php - 我应该使用什么样的连接,或者我应该为此制作模型?
问题描述
我有 3 张桌子-carts
和.cart_products
products
它们的结构如下所示:
推车:
id, employee_id, name, paid
购物车产品:
id, cart_id, product_id, amount
产品:
id, name, price
现在在我的代码中,我抓取了所有未付费的购物车:
$carts = Cart::where('paid', false)->select('id')->get();
并遍历它们:
foreach ($carts as $key) {
$cart_products = DB::table('cart_products')
->where('cart_id', $key->id)
->get();
$returnedCarts[] = [
'id' => $key->id,
'name' => $key->name,
'products'=> $cart_products
];
}
return response()->json($returnedCarts);
现在我的问题是如何更改包含 JSON 的产品:
{
"id": 1,
"name": null,
"products": [ //this is the cart_products table
{
"id": 1,
"cart_id": 1,
"product_id": 1,
"amount": 2,
"created_at": null,
"updated_at": null
}
]
},
进入这个:
{
"id": 1,
"name": null,
"products": [ //this is data from the products table
{
"product_id": 1,
"amount": 2, //but this is from the cart_products table
"name": "This product name",
"price" "$9,49"
}
]
},
在 foreach 循环中没有额外的查询。我应该使用什么样的联接?我应该更改我的代码还是应该使用模型而不是 DB 外观?
任何帮助将非常感激。
解决方案
您应该使用模型,因为您可以预先加载产品并保存一些查询(稍后阅读更多内容),并且通过使用模型,您可以利用 Eloquent API 资源来更好地控制输出(哪些字段,按什么顺序,从哪里得到它们,等等)。
N+1 查询问题
您现在正遭受N+1 查询问题的困扰,因为您获得了所有N 个未付费购物车(1 个查询),并且对于每个人,您都获得了他们的产品(N 个查询,每个购物车一个)。
实现模型关系
在购物车模型中,您可以像这样设置与产品的关系:
public function products()
{
return $this->belongsToMany('App\Product')->withPivot('amount');
}
您还可以添加一个查询范围,以简单地将告诉您购物车未付款的 where 条件保留在模型中而不是控制器中(稍后您将了解如何使用它):
public function scopeUnpaid($query)
{
return $query->where('paid', false);
}
API 资源
要实现 Eloquent API 资源,您必须:
- 使用 artisan 为 Cart 和 Product 创建 API 资源类:
php artisan make:resource Cart
php artisan make:resource Product
这些命令将创建两个文件
app/Http/Resources/Cart.php
和app/Http/Resources/Product.php
.
- 编辑购物车资源以在输出中显示您想要的字段,否则将返回所有购物车字段:
// Do not forget the use statement at the top
use App\Http\Resources\Product as ProductResource;
// Then replace the toArray method
public function toArray($request)
{
// $this refers to the current Cart instance
return [
'id' => $this->id,
'name' => $this->name,
// This line tells to render each product of this cart with the Product API Resource,
// in this way you can also control how each product model will be displayed
// in the json response
'products' => ProductResource::collection($this->products)
];
}
- 编辑 Product 资源以按照您想要的方式显示输出:
public function toArray($request)
{
// $this refers to the current Product instance
// As you requested, here you can set the field and it's value.
return [
'product_id' => $this->id,
// this field is taken from the cart_product table, that is loaded
// as you specified to load the amount attribute with the ->withPivot('amount')
// instruction in your products() relation
'amount' => $this->pivot->amount,
'name' => $this->name,
'price' => $this->price
];
}
在控制器中,您现在可以预先加载未付费购物车的所有产品,并使用 API 资源编辑将作为响应发送的内容,以仅显示您需要的属性。
// Do not forget to import the Cart model and the Cart Resource at the top
use App\Cart;
use App\Http\Resources\Cart as CartResource;
public function your_method()
{
// You can use the unpaid() query scope you added earlier
// as a simple shorthand to ->where('paid', false') function
// on the query builder.
// ->with('products') will eager-load the products relationship
// and therefore retrive the products associated to the carts you
// are gonna retrive with just one additional query, not one for each cart.
$carts = Cart::unpaid()->with('products')->get();
return CartResource::collection($carts);
}
推荐阅读
- c++ - 如何将 nodemcu 微控制器的传感器信息输出格式化为 JSON?
- android - 如何在 android 中使用 expresso 模拟一个类?
- data-mining - 如何设置 csv 或 txt 文件以上传到 weka?
- c - 如何在 C 中正确存储结构
- json - 如何从 raw.github URL 中提取 JSON 数据并将其存储在变量中?
- python - 如何在 python 中将数据(或单点)添加到现有的 3d 散点图
- django-models - “无效数据。需要字典,但得到了 SerializerMetaclass。” - DRF 串行器
- c++ - 将范围从容器复制到自身安全还是产生运行时错误?
- aws-lambda - 如何通过 aws lambda 让 winston-cloudwatch 工作?
- google-cloud-platform - google-cloud-videointelligence - TimeoutError 开始于 10 月 5 日