Laravel REST API中JsonResource遍历输出多对多genres关联数据
Laravel API 关联体裁返回实现方案
1. 控制器层预加载关联(解决N+1查询问题)
当前控制器直接查询分页数据未预加载genres关联,循环访问关联时会产生N+1性能问题,修改index方法如下:
public function index() { return MovieResource::collection(Movie::with('genres')->paginate()); }
2. 改造MovieResource返回关联数据
不需要手动写foreach遍历关联,Laravel提供了更优雅的处理方式,有两种可选用法:
- 简单场景直接映射字段
直接在genres字段处用集合map方法格式化返回数据即可:public function toArray($request) { return [ 'id' => $this->id, 'name' => $this->name, 'status' => $this->status, 'image_path' => url()->to('/images/' . $this->image_path), 'genres' => $this->genres->map(fn($genre) => [ 'id' => $genre->id, 'name' => $genre->name ]) ]; } - 复用场景使用独立Genre资源(推荐)
如果后续其他接口也需要返回体裁数据,先执行Artisan命令生成Genre资源类:
修改生成的php artisan make:resource GenreResourceGenreResource.php的toArray方法:
再在MovieResource中调用Genre资源集合返回,搭配public function toArray($request) { return [ 'id' => $this->id, 'name' => $this->name ]; }whenLoaded避免未预加载时触发额外查询:public function toArray($request) { return [ 'id' => $this->id, 'name' => $this->name, 'status' => $this->status, 'image_path' => url()->to('/images/' . $this->image_path), 'genres' => GenreResource::collection($this->whenLoaded('genres')) ]; }
两种写法最终返回的数据结构完全一致,单条电影数据返回格式示例:
{ "id": 1, "name": "星际穿越", "status": 1, "image_path": "http://your-app-domain/images/interstellar.png", "genres": [ {"id": 2, "name": "科幻"}, {"id": 5, "name": "剧情"} ] }
内容的提问来源于stack exchange,提问作者Illia
相关产品推荐
相关产品推荐

