是否存在可匹配给定表结构远层关联的Laravel关联方法?
优化方案
你原来的写法存在N+1查询性能问题,遍历每条关联记录都会单独发起一次ContactTag查询,数据量稍大时性能损耗非常明显。你完全可以通过自定义关联或者单次联表查询实现需求,两种可行方案如下:
方案1:直接单次联表查询获取结果
不需要额外定义关联,直接用查询构造器一次查询拿到所有符合要求的ContactTag id:
$contactTagIds = ContactTag::query() ->select('contact_tags.id') ->join('contact_list_tags', 'contact_tags.contact_id', '=', 'contact_list_tags.contact_id') ->join('list_tags', function ($join) { // 同时匹配list_tag关联和tag_id对应关系 $join->on('contact_list_tags.list_tag_id', '=', 'list_tags.id') ->on('contact_tags.tag_id', '=', 'list_tags.tag_id'); }) ->where('list_tags.list_id', $list->id) ->pluck('id');
得到的$contactTagIds就是你原来代码里$listContacts数组的完全等价结果,全程只有1次SQL查询。
方案2:在List模型中自定义contactTags关联
如果你希望像$list->contactTags()这样链式调用获取结果,直接在List模型中添加如下方法即可:
public function contactTags() { return ContactTag::query() ->select('contact_tags.*') ->join('contact_list_tags', 'contact_tags.contact_id', '=', 'contact_list_tags.contact_id') ->join('list_tags', function ($join) { $join->on('contact_list_tags.list_tag_id', '=', 'list_tags.id') ->on('contact_tags.tag_id', '=', 'list_tags.tag_id'); }) ->where('list_tags.list_id', $this->id); }
之后调用非常灵活:
- 拿所有ContactTag模型:
$list->contactTags()->get() - 只拿id数组:
$list->contactTags()->pluck('id') - 追加查询条件:
$list->contactTags()->where('xxx', $xxx)->get()
补充说明
你提到的$list->tagContacts()->contactTags()写法无法直接实现:tagContacts()返回的是HasManyThrough查询构造器,不是ContactListTag模型实例,只有对单个ContactListTag实例才能调用它的关联方法。如果需要给单条ContactListTag关联对应的ContactTag,可以在ContactListTag模型中定义contactTag一对一关联即可。
内容的提问来源于stack exchange,提问作者SeaBass
相关产品推荐
相关产品推荐

