如何在Laravel中为预加载关联添加查询条件?
给Laravel预加载关联添加查询条件的几种方法
这个场景我经常碰到,Laravel里给预加载关联加条件其实分好几种情况,看你是临时在查询里加,还是想让模型默认预加载就带条件,我给你逐个说明:
1. 查询时临时添加条件(最常用)
如果只是某个控制器方法里需要带条件的预加载,不想改动模型默认逻辑,直接在with()里用闭包就行,嵌套关联用点语法或者嵌套闭包都可以:
比如你要筛选状态为active的Block,同时只加载类型为text的Field,以及已发布的Data,可以这么写:
public function get() { $pages = Page::with([ // 给blocks加基础条件 'blocks' => function ($query) { $query->where('status', 'active'); // 如果是多对多关联,要筛选中间表字段的话用wherePivot // $query->wherePivot('position', '>', 5); }, // 给blocks下的fields加条件,点语法更简洁 'blocks.fields' => function ($query) { $query->where('type', 'text'); }, // 给fields下的data加条件 'blocks.fields.data' => function ($query) { $query->where('is_published', true); } ])->get(); return $pages; }
不用担心模型里的$with默认预加载冲突——Laravel会自动用你在with()里的闭包替换默认逻辑,不会重复加载。
2. 给模型关联永久加条件
如果所有地方用到这个关联都需要同一个条件,直接修改模型的关联方法就行:
比如让Page默认只关联active的Block:
class Page extends Model { protected $with = ['blocks']; public function blocks() { // 直接在关联里追加where条件 return $this->belongsToMany('\App\Block')->where('status', 'active'); } }
要是想更灵活(有时候要带条件,有时候不需要),可以用本地作用域:
先在Block模型里定义作用域:
class Block extends Model { protected $with = ['fields']; public function scopeActive($query) { return $query->where('status', 'active'); } public function fields() { return $this->hasMany('\App\Fields'); } }
然后在Page的关联里调用这个作用域:
public function blocks() { return $this->belongsToMany('\App\Block')->active(); }
需要不带条件的关联时,再额外定义一个方法就行,比如allBlocks():
public function allBlocks() { return $this->belongsToMany('\App\Block'); }
3. 覆盖模型默认预加载
如果模型的$with默认加载了所有关联,但你在某个查询里想完全替换成带条件的,可以先用without()去掉默认预加载,再重新定义:
$pages = Page::without('blocks') ->with(['blocks' => function ($query) { $query->where('status', 'active'); }]) ->get();
这个方法适合需要完全替换默认预加载逻辑的场景。
内容的提问来源于stack exchange,提问作者crond
相关产品推荐
相关产品推荐

