Laravel Eloquent如何获取未入库或库存为0的Product集合?
解决Laravel中获取指定仓库缺失或库存为0的产品集合问题
首先我们需要调整模型关联让查询更顺畅,然后实现missingProduct方法:
步骤1:完善Product模型的关联
给Product模型添加与中间表WarehouseProduct的关联,方便后续查询:
class Product extends Model { protected $fillable = [ 'name', 'item_number', // ... ]; // 关联仓库产品库存记录 public function warehouseProducts() { return $this->hasMany(WarehouseProduct::class); } }
步骤2:实现Warehouse模型的missingProduct方法
这里提供两种高效的实现方式,你可以根据场景和习惯选择:
方式一:Eloquent风格实现(推荐,代码更直观)
use Illuminate\Support\Facades\DB; class Warehouse extends Model { protected $fillable = [ 'name', 'address', // ... ]; public function products() { return $this->hasMany(WarehouseProduct::class); } public function missingProduct() { return Product::whereDoesntExist(function ($query) { // 筛选当前仓库无记录的产品 $query->select(DB::raw(1)) ->from('warehouse_products') ->whereColumn('warehouse_products.product_id', 'products.id') ->where('warehouse_products.warehouse_id', $this->id); }) ->orWhereHas('warehouseProducts', function ($query) { // 筛选当前仓库有记录但库存为0的产品 $query->where('warehouse_id', $this->id) ->where('amount', 0); }) ->get(); } }
方式二:左连接实现(大数据量场景性能更优)
class Warehouse extends Model { // ... 其他代码 public function missingProduct() { return Product::leftJoin('warehouse_products', function ($join) { $join->on('products.id', '=', 'warehouse_products.product_id') ->where('warehouse_products.warehouse_id', $this->id); }) ->where(function ($query) { // 匹配两种情况:无仓库记录 或者 库存为0 $query->whereNull('warehouse_products.id') ->orWhere('warehouse_products.amount', 0); }) ->select('products.*') // 仅返回产品表字段 ->distinct() // 避免重复结果 ->get(); } }
额外优化:添加多对多关联(可选)
如果希望更直接地在Warehouse和Product之间建立多对多关联,可以修改Warehouse模型的products方法:
public function products() { return $this->belongsToMany(Product::class, 'warehouse_products') ->withPivot('amount'); // 携带库存字段 }
此时也可以用更直观的方式实现missingProduct(虽然会多一次查询,但代码可读性更高):
public function missingProduct() { // 获取当前仓库已有记录的产品ID $existingIds = $this->products()->pluck('products.id'); // 获取当前仓库库存为0的产品ID $zeroStockIds = $this->products()->wherePivot('amount', 0)->pluck('products.id'); return Product::whereNotIn('id', $existingIds) ->orWhereIn('id', $zeroStockIds) ->get(); }
核心逻辑说明
所有实现方式的核心都是筛选两类产品:
- 完全没有在当前仓库的
warehouse_products表中留下记录的产品 - 在当前仓库有记录,但
amount字段等于0的产品
内容的提问来源于stack exchange,提问作者netdjw
相关产品推荐
相关产品推荐

