
本文详解为何在 paginate() 后调用 with() 会报错“Method Illuminate\Database\Eloquent\Collection::with does not exist”,并提供正确加载关联数据的实践方案。
本文详解为何在 `paginate()` 后调用 `with()` 会报错“method illuminate\database\eloquent\collection::with does not exist”,并提供正确加载关联数据的实践方案。
在 Laravel 中,with() 是 Eloquent 查询构建器(Builder)上的方法,用于预加载关联关系,从而避免 N+1 查询问题。但它必须在查询执行前调用——即在 get()、first()、paginate() 等终止性方法之前使用。一旦调用了 paginate(),Eloquent 就会执行 SQL 查询并返回一个 LengthAwarePaginator 实例(其内部封装了 Collection),此时链式调用已脱离 Builder 上下文,后续再调用 with() 就会触发错误:
Method Illuminate\Database\Eloquent\Collection::with does not exist.
这是因为 paginate() 返回的是结果集(分页器对象),而非查询构建器,而 Collection 类本身不支持 with() 方法。
✅ 正确写法:with() 必须置于 paginate() 之前
以下为修复后的标准写法:
public function getTaskDetails()
{
return ProductionTask::query()
->whereUserCanSee()
->latest()
->when($this->renderByDate, function ($query) {
return $query->sortBy('created_at');
})
->with(['assignmentTests' => function ($q) {
if ($this->renderByRating) {
$q->orderBy('rating', 'desc');
}
}])
->paginate(15); // ← paginate() 是终止方法,必须放在最后(除 with() 外)
}? 注意:sortBy('created_at') 在数据库层面无效(它是 Collection 方法),若需按日期排序应使用 orderBy('created_at');latest() 默认按 created_at DESC 排序,与 orderBy('created_at', 'desc') 等效。若 $this->renderByDate 为真时需升序排列,请显式写为 ->orderBy('created_at', 'asc')。
⚠️ 常见误区与替代方案
❌ 错误:->paginate()->with(...)->get()
→ paginate() 已返回分页器,后续 with() 无意义且报错。❌ 错误:->get()->with(...)
→ get() 返回 Collection,同样不支持 with()。-
✅ 替代方案(如需动态控制预加载):
$query = ProductionTask::query()->whereUserCanSee()->latest(); if ($this->renderByDate) { $query->orderBy('created_at', 'asc'); // 推荐用 orderBy 而非 sortBy } $query->with(['assignmentTests' => fn ($q) => $this->renderByRating ? $q->orderBy('rating', 'desc') : $q ]); return $query->paginate(15);
? 总结
- with() 是 Builder 方法,仅对未执行的查询生效;
- 所有终止方法(get()、first()、paginate()、count() 等)都会结束查询链;
- 预加载逻辑必须在终止方法调用前完成;
- 分页场景下,with() 应紧邻 paginate() 之前,且注意关联闭包中避免无条件 return(Laravel 会自动处理闭包逻辑,无需显式 return $q)。
遵循此原则,即可安全、高效地实现带关联预加载的分页查询。










