【发布时间】:2020-03-14 10:52:42
【问题描述】:
让我们使用典型的帖子/标签示例。假设我想提取一些帖子的详细信息。我是一个聪明的开发者,想要限制数据库查询,所以我渴望将关系加载到标签。
<?php
class Post extends Model {
public function tags() { return $this->belongsToMany(Tag::class); }
}
class Tag extends Model {
public function posts() { return $this->belongsToMany(Post::class); }
}
$posts = Post::query()->with("tags")->where("title", "like", "foo%")->get();
到目前为止,一切都很好。我的数据库的查询日志显示了两个查询:
select * from `posts` where `title` like 'foo%' and `posts`.`deleted_at` is null;
select `tags`.*, `post_tag`.`post_id` as `pivot_post_id`, `post_tag`.`tag_id` as `pivot_tag_id`
from `tags` inner join `post_tag` on `tags`.`id` = `post_tag`.`tag_id`
where `post_tag`.`post_id` in (19, 880, 1462, 2712, 2713, 2717);
我现在可以毫无问题地处理帖子和标签。例如,我可以运行此代码而无需任何进一步的数据库查询:
foreach ($posts as $post) {
echo $post->title . "(" . implode(",", $post->tags->pluck("name")->all()) . ")";
}
这告诉我关系中的数据已按预期保存到集合 $posts 中。
所以,我的问题是:为什么调用 $posts->toArray() 或 $posts->toJson() 会导致 另一个 查询我的数据透视表中的 每个项目,拉已存储在集合中的相同数据?
select `tags`.*, `post_tag`.`post_id` as `pivot_post_id`, `post_tag`.`tag_id` as `pivot_tag_id`
from `tags` inner join `post_tag` on `tags`.`id` = `post_tag`.`tag_id`
where `post_tag`.`post_id` = 19 limit 1;
select `tags`.*, `post_tag`.`post_id` as `pivot_post_id`, `post_tag`.`tag_id` as `pivot_tag_id`
from `tags` inner join `post_tag` on `tags`.`id` = `post_tag`.`tag_id`
where `post_tag`.`post_id` = 880 limit 1;
...
select `tags`.*, `post_tag`.`post_id` as `pivot_post_id`, `post_tag`.`tag_id` as `pivot_tag_id`
from `tags` inner join `post_tag` on `tags`.`id` = `post_tag`.`tag_id`
where `post_tag`.`post_id` = 2717 limit 1;
有什么方法可以防止这些额外的查询发生吗?
【问题讨论】:
-
您是否将数据“附加”到具有
appends属性的模型中?用访问器做什么? -
不,我并不总是需要额外的数据,所以不想强迫它。
-
你能展示 Post 模型的其余部分吗
-
在我的电脑上,它会导致 3 次查询(如果以前从未做过),一个限制为 1,一个选择 *,然后是枢轴查询
-
啊,很高兴你找到它 :)
标签: php mysql laravel laravel-query-builder