使用Eloquent构建葡萄酒类型筛选复杂查询的问题
解决Laravel Eloquent查询葡萄酒类型的问题
先确认模型关联是否正确
首先必须确保三个模型的关联关系定义准确,否则whereHas方法会失效:
- Wine模型:
class Wine extends Model { public function variety() { return $this->belongsTo(Variety::class); } }
- Variety模型:
class Variety extends Model { public function wines() { return $this->hasMany(Wine::class); } public function type() { return $this->belongsTo(Type::class); } }
- Type模型:
class Type extends Model { public function varieties() { return $this->hasMany(Variety::class); } }
修复你的whereHas查询
你之前的代码问题在于嵌套关联的写法错误,whereHas需要通过闭包逐层嵌套检查关联:
$redWines = Wine::whereHas('variety', function ($query) { $query->whereHas('type', function ($subQuery) { $subQuery->where('id', 1); }); }) // 在这里追加其他筛选条件,比如库存、标签 ->where('stock', '>', 0) ->whereHas('tags', function ($tagQuery) { $tagQuery->where('name', 'like', '%organic%'); }) ->get();
更高效的替代方案:使用关联查询(Join)
如果查询涉及多个筛选条件,用join可以减少数据库查询次数,性能更优:
$redWines = Wine::join('varieties', 'wines.variety_id', '=', 'varieties.id') ->join('types', 'varieties.type_id', '=', 'types.id') ->where('types.id', 1) // 添加其他筛选条件 ->where('wines.stock', '>', 0) ->select('wines.*') // 仅选择葡萄酒表字段,避免字段冲突 ->get();
可复用的查询范围封装
如果需要频繁按类型筛选,可以在Wine模型中封装查询范围:
public function scopeOfType($query, $typeId) { return $query->whereHas('variety', function ($q) use ($typeId) { $q->whereHas('type', function ($sq) use ($typeId) { $sq->where('id', $typeId); }); }); }
调用时会更简洁:
$redWines = Wine::ofType(1)->where('stock', '>', 0)->get();
内容的提问来源于stack exchange,提问作者Marko Stojanovic
相关产品推荐
相关产品推荐

