Laravel 5.6使用with()仍返回所有关联关系问题求助
这种情况我碰到过好多次,大概率是你的User模型或者响应处理环节有自动加载关联的配置,咱们一步步来排查:
1. 检查User模型的$with属性
这是最常见的原因!Laravel的Eloquent模型里,$with属性会默认预加载指定的关联,不管你在控制器里有没有手动调用with(),甚至直接find()的时候都会自动加载这些关联。
打开你的User.php模型文件,找一下有没有类似这样的代码:
protected $with = ['meta', 'roles', 'company'];
如果里面包含了company或者其他你不想默认返回的关联,把它们从数组里删掉就好。如果不需要任何默认预加载,直接把整个$with属性删掉也行。
2. 检查模型的toArray()/toJson()方法
如果你在User模型里重写了toArray()方法,看看是不是手动添加了所有关联的字段,比如:
public function toArray() { $attributes = parent::toArray(); $attributes['company'] = $this->company; // 这里会强制加载company关联 $attributes['meta'] = $this->meta; return $attributes; }
如果是这样,要么删掉这些手动添加的关联字段,要么改成只在关联已加载的时候才添加:
if ($this->relationLoaded('company')) { $attributes['company'] = $this->company; }
3. 检查Eloquent资源类(如果用了的话)
如果你用了Laravel的API资源(比如UserResource),看看资源类的toArray()方法是不是返回了所有关联,比如:
public function toArray($request) { return [ 'id' => $this->id, 'name' => $this->name, 'company' => new CompanyResource($this->company), // 这里会触发关联加载 'meta' => new MetaResource($this->meta), 'roles' => RoleResource::collection($this->roles), ]; }
如果不需要返回company,直接把这个字段删掉就行;如果需要根据场景动态返回,可以加个条件判断,比如:
'company' => $this->when($this->relationLoaded('company'), new CompanyResource($this->company)),
4. 检查全局查询作用域
看看User模型的boot()方法里有没有添加全局作用域,强制给所有查询加关联:
protected static function boot() { parent::boot(); static::addGlobalScope('withCompany', function ($query) { $query->with('company'); // 这个全局作用域会让所有User查询都加载company }); }
如果有这样的代码,要么删掉这个全局作用域,要么改成只在特定场景手动调用,而不是全局生效。
快速验证方法
你可以在控制器的show方法里,查询完之后直接打印模型实例,看看是不是查询阶段就已经加载了所有关联:
$user = User::with('meta', 'roles')->find($user_id); dd($user); // 看输出里的relations数组,有没有company
如果dd的时候就有company,那就是查询环节的问题($with或全局作用域);如果dd的时候没有,但接口响应里有,那就是响应转换环节的问题(toArray或资源类)。
内容的提问来源于stack exchange,提问作者user3574492

