Laravel 9多对多关联如何存取中间表pivot的额外字段数据
Laravel 9 多对多关联配置及中间表字段操作方案
一、模型关联定义
Laravel 9 中双向多对多关系统一使用belongsToMany方法定义,需在两个关联模型中分别配置关联关系,同时通过withPivot声明中间表的额外业务字段。
你的中间表名product_shop符合Laravel默认的字母顺序拼接约定,以下代码显式传入表名和外键参数,避免后续模型调整引发关联异常:
- 店铺模型(
app/Models/Shop.php)关联定义:
public function products() { return $this->belongsToMany( Product::class, 'product_shop', 'shop_id', 'product_id' )->withPivot('number'); // 声明中间表需要读写的number字段 }
- 商品模型(
app/Models/Product.php)反向关联定义:
public function shops() { return $this->belongsToMany( Shop::class, 'product_shop', 'product_id', 'shop_id' )->withPivot('number'); }
注意:product_shop表直接用product_id+shop_id做联合主键即可,无需额外新增自增ID字段,Laravel多对多关联原生支持该表结构。如果中间表包含created_at、updated_at时间戳字段,可以在关联定义后链式调用->withTimestamps()方法自动维护。
二、中间表number字段写入/更新操作
所有多对多关联的中间表操作,都可以直接通过关联对象调用内置方法完成,无需手动写SQL操作中间表:
- 新增关联同时写入库存:使用
attach方法,第二个参数传入中间表额外字段的键值对$shop = Shop::find(1); // 给1号店铺关联3号商品,设置库存为100 $shop->products()->attach(3, ['number' => 100]); // 批量关联多个商品,分别设置对应库存 $shop->products()->attach([ 2 => ['number' => 50], 4 => ['number' => 200], 5 => ['number' => 30] ]); - 同步关联关系(最常用的批量更新场景):使用
sync方法,传入最终需要保留的关联列表,方法会自动新增缺失关联、删除不在列表内的旧关联、更新已有关联的中间字段// 最终1号店铺仅保留2、4号商品的关联,对应库存更新为传入值 $shop->products()->sync([ 2 => ['number' => 60], 4 => ['number' => 180] ]); - 更新已有关联的中间字段:使用
updateExistingPivot方法,无需解绑重连关联// 将1号店铺下3号商品的库存更新为120 $shop->products()->updateExistingPivot(3, ['number' => 120]); - 中间字段增减操作:直接通过
newPivotStatement操作中间表,性能更高// 将1号店铺下3号商品的库存扣减5 $shop->products()->newPivotStatement() ->where('shop_id', $shop->id) ->where('product_id', 3) ->decrement('number', 5);
三、中间表number字段查询操作
- 读取关联数据时获取中间表字段:关联配置
withPivot后,拿到关联模型实例即可通过pivot动态属性访问中间表字段// 查询1号店铺下所有商品及对应库存 $shop = Shop::with('products')->find(1); foreach ($shop->products as $product) { echo "商品名称:{$product->name},店铺库存:{$product->pivot->number}"; } - 按中间表字段做条件筛选:使用
wherePivot方法添加查询条件// 查询1号店铺下库存大于100的商品 $highStockProducts = $shop->products() ->wherePivot('number', '>', 100) ->get(); // 查询所有上架了5号商品、且商品库存大于0的有效店铺 $validShops = Shop::whereHas('products', function($query) { $query->where('products.id', 5) ->wherePivot('number', '>', 0); })->get();
内容的提问来源于stack exchange,提问作者aref razavi
相关产品推荐
相关产品推荐

