Laravel 在 with 查询中只查询个别字段

刚答了一篇帖子, 算比较常用的技巧,整理一下分享出来。

在使用 Laravel 的关联查询中,我们经常使用 with 方法来避免 N+1 查询,但是 with 会将目标关联的所有字段全部查询出来,对于有强迫症的我们来说,当然是不允许的。

这时候我们可以使用下面的技巧在使用 with 时只查询目标关联的部分字段:

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

但是每次查询都写得这么繁琐真的好么?不如利用 Laravel 的范围查询将其封装起来:

在 Model 基类中定义一个范围查询(或者使用 Trait)

class BaseModel extends \Eloquent{
    public function scopeWithOnly($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)->withOnly('user', ['username'])->get();
本帖已被设为精华帖!
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 9

如果关联关系是多层嵌套需要怎么才能实现,例如 ...->with('product.productImg')->get()

7年前 评论
小怪兽

就是会不会感觉有点多余,因为我感觉你这样在查的时候也是把要查的字段以数组形式放进去 跟外面写貌似都一样的性质,还是说我理解错了呢

7年前 评论

@ruanqi with查询结果空是因为你的查询字段不包含你的关联字段, 就比如 拿ID关联的话, 你就得 select() 里必须包含ID, 要么就返回空

7年前 评论

@2016 为啥没有包含关联字段就会为空呢,文档上没找到说明

6年前 评论

我想问下 为什么我 的是为空呢 ?
$faqs = Faq::limit(5)
->withOnly('reply', ['id', 'content'])
->get();

6年前 评论

是按你说那样在baseModel 中添加了你的那个方法

6年前 评论

我直接用with 时查询了所有

6年前 评论

我也觉得多余了。
不过可能安全性能好点?比如缺省某些字段。

我改写了一下,因为我主键名不为 id,所以楼主那样就会 null 了。

    public function scopeWithOnly(object $query, string $relation, array $columns)
    {
        return $query->with([$relation => function ($query) use ($columns) {

            if (count($columns) == 1) {
                $columns = array_merge(['id'], $columns);
            }
            $query->select($columns);
        }]);
    }
5年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!