You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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资源类标准化返回结构:
    1. 课程内容资源:php artisan make:resource CourseContentResource
      public function toArray($request)
      {
          return [
              'id' => $this->id,
              'title' => $this->title,
              'content_body' => $this->content_body,
              'sort_order' => $this->sort_order
          ];
      }
      
    2. 课程资源: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.26 21:45:03