Laravel 8 如何合并集合与查询构建器后使用分页功能
错误原因
union() 方法仅支持接收另一个查询构建器实例作为入参,你的代码中$processingRequests调用了get()方法后已经转为Collection集合对象,传入union()就会触发类型不匹配的报错。
解决方案
提供两种适配不同场景的实现方式:
方案一:重构逻辑使用原生SQL union(性能最优,优先选择)
如果FormsController::checkUserPermissionToConsultForm的权限校验逻辑可以转化为SQL查询条件,就不要提前调用get(),让两个变量都保持查询构建器实例,直接用原生union后分页即可:
public function getRequests(){ $closedRequests = request::join('request_logs', 'request_logs.request_id', '=', 'requests.id') ->select("requests.id", "requests.user_id", "requests.form_type", "requests.created_at", "requests.request_status") ->whereNotIn('request_status', [-2, 0]) ->where('request_logs.user_id', Auth::user()->id); $processingRequests = request::select("requests.id", "requests.user_id", "requests.form_type", "requests.created_at", "requests.request_status") ->where('request_status', 0) // 此处将权限校验逻辑转化为SQL where条件,例:关联权限表做存在判断等 ->whereRaw(/* 转化后的权限判断SQL逻辑 */); $result = $closedRequests->union($processingRequests) ->orderBy('created_at', 'desc') ->paginate(5); return $result; }
方案二:合并集合后手动生成分页器(适配权限逻辑无法转SQL的场景)
如果权限校验必须在PHP层处理,就先执行两个查询拿到集合,合并后手动实例化分页对象:
public function getRequests(){ // 执行第一个查询拿到集合 $closedRequests = request::join('request_logs', 'request_logs.request_id', '=', 'requests.id') ->select("requests.id", "requests.user_id", "requests.form_type", "requests.created_at", "requests.request_status") ->whereNotIn('request_status', [-2, 0]) ->where('request_logs.user_id', Auth::user()->id) ->get(); // 执行第二个查询并做权限过滤 $processingRequests = request::select("requests.id", "requests.user_id", "requests.form_type", "requests.created_at", "requests.request_status") ->where('request_status', 0) ->get() ->filter(function ($request) { return FormsController::checkUserPermissionToConsultForm($request, true); }); // 合并集合、去重、排序 $allRequests = $closedRequests->merge($processingRequests) ->unique('id') ->sortByDesc('created_at'); // 手动分页参数处理 $perPage = 5; $currentPage = request()->input('page', 1); $currentPageItems = $allRequests->slice(($currentPage - 1) * $perPage, $perPage)->values(); // 生成分页器 $paginatedResult = new \Illuminate\Pagination\LengthAwarePaginator( $currentPageItems, $allRequests->count(), $perPage, $currentPage, [ 'path' => request()->url(), 'query' => request()->query() ] ); return $paginatedResult; }
注意:方案二需要一次性查询所有符合条件的数据再做切割,数据量较大时性能较差,仅适用于数据量可控的场景。
内容的提问来源于stack exchange,提问作者Achraf Ben Soltane
相关产品推荐
相关产品推荐

