如何在Laravel API中基于ERD实现一对多关系的存储与展示?
Laravel API 一对多关系(课程-课程内容)全流程实现
1. 匹配ERD结构创建数据库迁移
按照ERD定义的课程主表、课程内容子表结构,分别创建对应迁移文件:
- 执行命令创建课程表迁移:
php artisan make:migration create_courses_table
编辑迁移文件中的up方法,定义主表字段:Schema::create('courses', function (Blueprint $table) { $table->id(); $table->string('title'); $table->text('description')->nullable(); $table->timestamps(); }); - 执行命令创建课程内容表迁移:
php artisan make:migration create_course_contents_table
编辑迁移文件中的up方法,定义带外键关联的子表字段,配置级联删除规则:Schema::create('course_contents', function (Blueprint $table) { $table->id(); $table->foreignId('course_id')->constrained()->cascadeOnDelete(); $table->string('title'); $table->longText('content_body'); $table->integer('sort_order')->default(0); $table->timestamps(); }); - 执行迁移命令同步表结构:
php artisan migrate
2. 定义模型关联关系
按照一对多的关联规则,在对应模型中设置关联方法:
- 主模型
app/Models/Course.php:定义一对多关联,即单个课程包含多条课程内容class Course extends Model { protected $fillable = ['title', 'description']; public function contents() { return $this->hasMany(CourseContent::class); } } - 子模型
app/Models/CourseContent.php:定义反向关联,即单条课程内容归属于单个课程class CourseContent extends Model { protected $fillable = ['course_id', 'title', 'content_body', 'sort_order']; public function course() { return $this->belongsTo(Course::class); } }
3. 实现带关联数据的存储接口
提交课程创建请求时,可一次性传入课程基础信息+关联的课程内容列表,通过事务保证数据一致性:
- 创建表单验证类:
php artisan make:request StoreCourseRequest
配置嵌套字段的验证规则,保证传入的课程内容结构合法:public function rules() { return [ 'title' => 'required|string|max:255', 'description' => 'nullable|string', 'contents' => 'required|array|min:1', 'contents.*.title' => 'required|string|max:255', 'contents.*.content_body' => 'required|string', 'contents.*.sort_order' => 'integer|min:0' ]; } - 在
CourseController中编写store方法,通过数据库事务先创建课程主记录,再批量写入关联的课程内容:use Illuminate\Support\Facades\DB; use Illuminate\Support\Arr; public function store(StoreCourseRequest $request) { $validated = $request->validated(); DB::transaction(function () use ($validated) { $course = Course::create(Arr::except($validated, 'contents')); $course->contents()->createMany($validated['contents']); }); return response()->json(['message' => '课程创建成功'], 201); }
4. 实现关联数据的详情展示接口
查询课程详情时,一次性返回基础信息+关联的课程内容列表,通过预加载避免N+1查询问题:
- 创建API资源类标准化返回结构:
- 课程内容资源:
php artisan make:resource CourseContentResourcepublic function toArray($request) { return [ 'id' => $this->id, 'title' => $this->title, 'content_body' => $this->content_body, 'sort_order' => $this->sort_order ]; } - 课程资源:
php artisan make:resource CourseResource
配置延迟加载关联内容,避免冗余查询:public function toArray($request) { return [ 'id' => $this->id, 'title' => $this->title, 'description' => $this->description, 'contents' => CourseContentResource::collection($this->whenLoaded('contents')) ]; }
- 课程内容资源:
- 在
CourseController中编写show方法,预加载关联内容后通过资源类返回结构化数据:
注意使用public function show(string $id) { $course = Course::with('contents')->findOrFail($id); return new CourseResource($course); }with预加载关联数据,可避免循环查询带来的N+1性能问题 - 在
routes/api.php中注册对应路由:Route::post('/courses', [CourseController::class, 'store']); Route::get('/courses/{id}', [CourseController::class, 'show']);
内容的提问来源于stack exchange,提问作者muhammad refda
相关产品推荐
相关产品推荐

