Laravel 9根据请求参数过滤模型多对多关联数据方法
Laravel 多对多关联过滤主模型的正确实现
错误原因
你之前的写法不生效,核心是混淆了with()预加载过滤和关联存在性过滤的作用:
- 在
with()的关联闭包里加where条件,只会筛选预加载返回的关联数据,不会过滤主模型(房产Property)本身的查询结果 - 最终效果就是查询会返回所有符合search条件的房产,只有匹配ownerId的所有者会被预加载,不匹配的房产下owner关联为空,完全达不到「只返回指定所有者名下房产」的要求。
另外原有search逻辑中的orWhere没有做逻辑分组,后续追加其他where条件时会出现SQL逻辑优先级错误,导致搜索结果错乱。
实现代码
要过滤出绑定了指定所有者的房产,需要用whereHas()方法做关联存在性校验,该方法会基于关联关系筛选主模型结果,原有预加载逻辑保留即可:
$property = Property::query() ->when($request->search, function($query, $search) { // 用嵌套where给模糊查询条件分组,避免和后续过滤条件逻辑冲突 $query->where(function($subQuery) use ($search) { $subQuery->where('name', 'like', "%{$search}%") ->orWhere('name2', 'like', "%{$search}%") ->orWhere('city', 'like', "%{$search}%"); }); }) // 携带ownerId参数时,过滤关联了指定所有者的房产 ->when($request->ownerId, function($query, $ownerId) { $query->whereHas('owner', function($ownerQuery) use ($ownerId) { $ownerQuery->where('owner.id', $ownerId); }); }) ->select(['id', 'name', 'published']) // 预加载不需要额外加ownerId过滤,正常加载即可 ->with(['photo', 'owner', 'destiny']) ->get();
可选调整
如果你不需要返回房产下的全部所有者,只需要返回当前查询匹配的那个所有者信息,可以在with()的owner关联闭包里追加相同的id过滤条件:
->with([ 'photo', 'owner' => function($query) use ($request) { // 仅当传入ownerId时才过滤关联数据 if ($request->ownerId) { $query->where('owner.id', $request->ownerId); } }, 'destiny' ])
注意过滤owner id时要加上owner.表前缀,避免和中间表的同名字段产生歧义。Eloquent会自动处理多对多中间表的关联逻辑,不需要手动编写join语句。
内容的提问来源于stack exchange,提问作者Phyron
相关产品推荐
相关产品推荐

