Laravel 10多态关联查询返回null但父模型存在的解决方法
问题分析与解决方案
你的核心问题在于:withWhereHas 仅当闭包内存在实际查询条件时,才会自动过滤掉无 modelable 关联的记录。如果请求中的 firstName/lastName/email/phone 参数全为空,闭包不会添加任何约束,此时 withWhereHas 等价于普通的 with('modelable'),不会排除关联为空的 Application 记录。
解决步骤
要强制排除 modelable 为 null 的记录,你需要:
- 无论是否有筛选参数,都添加
has('modelable')约束,确保仅保留存在关联的Application; - 优化查询逻辑,避免
orWhereNull破坏其他条件的逻辑关系; - 根据是否有筛选参数,选择高效的关联加载方式。
修改后的完整代码
// 先判断是否存在modelable相关的筛选条件 $hasModelableFilters = $request->filled(['firstName', 'lastName', 'email', 'phone']); $applications = Application::query() ->where('submitted_at', '>=', Carbon::parse($request->input('from'))) ->where('submitted_at', '<=', Carbon::parse($request->input('to'))) // 用闭包包住company_id的条件,避免orWhereNull干扰其他查询逻辑 ->where(function ($query) use ($company) { $query->where('company_id', $company->id); if ($company->is_default) { $query->orWhereNull('company_id'); } }) ->when($request->input('affiliates'), function ($query, $affiliates) { $query->whereIn('affiliate_id', $affiliates); }) ->when($request->input('campaigns'), function ($query, $campaigns) { $query->whereIn('campaign_id', $campaigns); }) ->with(['redirect', 'campaign', 'affiliate']) // 强制筛选存在modelable关联的记录 ->has('modelable') // 根据是否有筛选条件选择关联加载方式 ->when($hasModelableFilters, function ($query) use ($request) { $query->withWhereHas('modelable', function ($query) use ($request) { if ($request->input('firstName')) { $query->where('AppFirstName', $request->input('firstName')); } if ($request->input('lastName')) { $query->where('AppLastName', $request->input('lastName')); } if ($request->input('email')) { $query->where('AppEmail', $request->input('email')); } if ($request->input('phone')) { $query->where('AppMobilePhone', $request->input('phone')); } }); }, function ($query) { // 无筛选条件时直接加载关联,避免不必要的子查询 $query->with('modelable'); }) ->orderBy('submitted_at', 'desc') ->paginate($request->input('perPage', 10)) ->onEachSide(1); if ($applications->isEmpty()) { return new ApiSuccessResponse(null, [ 'message' => 'No applications found.', ], 404); }
关键说明
has('modelable'):直接筛选出存在modelable关联的记录,从根源上排除关联为空的数据;- 用闭包包住
company_id条件:避免orWhereNull与其他where条件产生逻辑冲突,保证查询逻辑的正确性; when方法的使用:根据是否有筛选参数动态选择关联加载方式,提升查询效率。
内容的提问来源于stack exchange,提问作者Ryan H
相关产品推荐
相关产品推荐

