Laravel 5.5:嵌套查询与模型关联技术问询
解决Eloquent关联查询特定用户下符合条件的Shipment数据
嗨,我来帮你搞定这个查询需求!首先咱们得先确认模型之间的关联关系定义是正确的,这样后续的查询才能顺利跑起来。
第一步:确认模型关联定义
先把各个模型的关联方法写对,确保Eloquent能正确识别它们之间的关系:
User模型(User.php)
用户和运单是一对多关系,所以在User里定义shipments方法:
class User extends Model { public function shipments() { return $this->hasMany(Shipment::class); } }
Shipment模型(Shipment.php)
运单和状态历史是一对多关系,同时也可以通过hasManyThrough直接关联到Status(可选,但方便后续查询):
class Shipment extends Model { // 反向关联用户(可选) public function user() { return $this->belongsTo(User::class); } // 关联状态历史 public function statusHistories() { return $this->hasMany(StatusHistory::class); } // 可选:通过状态历史关联状态 public function statuses() { return $this->hasManyThrough(Status::class, StatusHistory::class); } }
StatusHistory模型
状态历史属于运单和状态:
class StatusHistory extends Model { public function shipment() { return $this->belongsTo(Shipment::class); } public function status() { return $this->belongsTo(Status::class); } }
第二步:执行查询获取目标数据
接下来就可以通过whereHas方法来过滤符合条件的Shipment了——这个方法的作用是筛选出拥有满足特定条件的关联模型的主模型,正好符合你的需求。
场景1:筛选StatusHistory中包含特定Status ID的Shipment
假设你要找用户ID为$userId的所有运单,且这些运单的状态历史中存在状态ID为$targetStatusId的记录:
// 替换成你的目标用户ID和状态ID $userId = 1; $targetStatusId = 5; $targetShipments = User::find($userId)->shipments() ->whereHas('statusHistories', function ($query) use ($targetStatusId) { // 指定状态历史的status_id等于目标值 $query->where('status_id', $targetStatusId); }) ->get();
场景2:筛选包含特定StatusHistory ID的Shipment
如果你的需求是找状态历史ID等于$targetHistoryId的运单(属于指定用户),只需要修改where条件即可:
$userId = 1; $targetHistoryId = 10; $targetShipments = User::find($userId)->shipments() ->whereHas('statusHistories', function ($query) use ($targetHistoryId) { $query->where('id', $targetHistoryId); }) ->get();
另一种写法:从Shipment模型出发查询
如果你更习惯从Shipment模型开始查询,也可以这样写,效果完全一致:
$targetShipments = Shipment::whereHas('user', function ($query) use ($userId) { $query->where('id', $userId); }) ->whereHas('statusHistories', function ($query) use ($targetStatusId) { $query->where('status_id', $targetStatusId); }) ->get();
补充说明
- 如果需要同时加载关联的StatusHistory或Status数据,可以在查询末尾加上
with(['statusHistories', 'statuses']),避免N+1查询问题。 whereHas默认是匹配存在至少一条符合条件的关联记录,如果你需要所有关联记录都符合条件,可以用whereHas(..., true)或者whereEveryHas(Laravel 8.57+版本支持)。
内容的提问来源于stack exchange,提问作者Felipe Peña
相关产品推荐
相关产品推荐

