如何在 Laravel 只查询关联模型的个别字段?

78

在使用 Laravel 的关联查询中,我们经常使用 with 方法来避免 N+1 查询,但是 with 会将目标关联的所有字段全部查询出来,接下来介绍一个能够读取关联模型个别字段的方法:

$topics = Topic::limit(2)->with(['user'=>function($query){
   $query->select('id','username');
}])->get();

接下来我们利用 Laravel 的 范围查询 将其封装起来,在 Model 基类中定义一个范围查询:

class BaseModel extends \Eloquent {
    public function scopeWithCertain($query, $relation, Array $columns)
    {
        return $query->with([$relation => function ($query) use ($columns){
            $query->select(array_merge(['id'], $columns));
        }]);
    }
}

在我们普通的 Model 类都继承基类:

class Topic extends BaseModel {
    public function user()
    {
        return $this->belongsTo('User');
    }
}

然后使用就很方便了:

$topics = Topic::limit(2)->withCertain('user', ['username'])->get();
讨论数量: 17

试试

$topics = Topic::limit(2)->with('user:id,username')->get();

会有惊喜。

很多时候,会关联多个模型, 那么 Topic::limit(2)->with('user:id,username', 'article:id,title')->get();Topic::limit(2)->with(['user:id,username', 'article:id,title'])->get();

3周前
XiaohuiLam

@zhuzhichao 哈,听君一席话,自挂东南枝。自觉文章白读了

3周前

听君一席话,圣斗士念书

3周前

@zhuzhichao 听君一席话, 少写多行代码

3周前

@XiaohuiLam
@韩众 应该归纳到,《不看源代码,找不到这种用法》系列 :sweat_smile:

3周前

学习了

2周前
aen233

@zhuzhichao 学习了.....谢谢♪(・ω・)ノ

2周前
aen233

@zhuzhichao with里面如果还有排序,要怎么写呢?是不是就必须在闭包里面写了?

2周前

@aen233 是的。有特殊的逻辑,就需要自己写了。

如果写成 user:id@desc,username@asc 也太难看了(也不会生效的),并且排序时也有可能有先后顺序的,例如按照名字排序,如果名字相同,按照创建时间排。

还是写个逻辑闭包吧。

2周前
aen233

@zhuzhichao 嗯嗯 谢谢啦,试了下如果写成 users:id,username@asc,会报Unknown column 'username@asc' in 'field list'。
后来是在关联关系上加了排序,然后with就只写字段了。

2周前

@aen233 我那个是随便写的错误代码。用来表达复杂逻辑是无法实现的。需要自己写逻辑了。 :sweat_smile:

2周前

@zhuzhichao 这种方法貌似只能用在with里面的关联关系是belongsTo的,hasMany的就不行,比如:

$users = User::limit(2)->with('articles:id,title')->get();
1周前

@linkphper 记得带上关联的字段,否则无法关联的

$users = User::limit(2)->with('articles:id,user_id,title')->get();

把你的 user_id 加上就好了

1周前

学习了,感谢分享

6天前

@zhuzhichao 感谢大佬,亲测有效!

6天前

学习了

6天前

文档有介绍这样用哦

5天前

  • 请注意单词拼写,以及中英文排版,参考此页
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`, 更多语法请见这里 Markdown 语法
  • 支持表情,使用方法请见 Emoji 自动补全来咯,可用的 Emoji 请见 :metal: :point_right: Emoji 列表 :star: :sparkles:
  • 上传图片, 支持拖拽和剪切板黏贴上传, 格式限制 - jpg, png, gif
  • 发布框支持本地存储功能,会在内容变更时保存,「提交」按钮点击时清空
  请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!