Laravel中添加单个访问器却加载关联资源的原因及关联存在性判断优化方案
解决Laravel中访问器导致关联关系被自动加载的问题
你的问题根源在于访问器里直接调用$this->profile会触发关联的懒加载,Laravel会自动把查询到的Profile实例存入模型的属性集合中,所以序列化JSON时会被一起输出。
最优解决方案:使用关联查询的exists()方法
不需要加载整个关联模型,直接用exists()检查关联记录是否存在,这种方式性能更高,也不会把Profile附加到模型属性里:
class User extends Model { protected $appends = ['has_profile']; // 可选:隐藏profile属性,双重保险防止意外输出 protected $hidden = ['profile']; public function profile() { return $this->hasOne(Profile::class); } public function getHasProfileAttribute() { // exists()会执行一个轻量的EXISTS查询,仅判断是否存在关联记录 return $this->profile()->exists() ? 1 : 0; } }
为什么原来的写法会出问题?
当你写$this->profile时,Laravel会自动执行$this->profile()->first(),并且把查询结果赋值给模型的关联属性容器,所以当模型序列化为JSON时,这个属性会被包含进去。
而用$this->profile()->exists()时,只是执行了一条SELECT EXISTS(...)的SQL语句,不会把任何关联模型实例附加到当前User模型上,完美符合你的需求。
备选方案:使用first()但不赋值
如果你不想用exists(),也可以直接调用关联查询的first(),但不要把结果赋值给模型属性:
public function getHasProfileAttribute() { return $this->profile()->first() ? 1 : 0; }
不过这种方式会查询整条Profile记录,性能不如exists()高效,所以更推荐第一种方案。
验证效果
现在当你执行User::find(1)并序列化为JSON时,输出会和你期望的一致:
"data": { "id": 270, "name": "John Doe", "mobile_number": "01234567890", "created_at": "2021-08-19T06:55:33.000000Z", "updated_at": "2021-08-19T06:55:33.000000Z", "deleted_at": null, "has_profile": 1 }
内容的提问来源于stack exchange,提问作者Prem Arumugam
相关产品推荐
相关产品推荐

