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

Laravel中如何为带外键的关联表编写Seeder数据填充

Laravel多对多中间表Seeder填充实现

前置代码修复

你现有Movie模型的多对多关联定义存在类名引用错误,关联目标写为了Menu::class,必须先修正为Genre::class,否则关联写入会报错,修正后代码:

class Movie extends Model
{
    use HasFactory;

    protected $fillable = ['name', 'status', 'image_path'];

    public function genres()
    {
        return $this->belongsToMany(Genre::class, 'genre_movie');
    }
}

实现思路

不需要手动硬编码genre_id、movie_id,直接通过Eloquent模型提供的多对多关联操作方法写入中间表,框架会自动获取对应记录的主键ID,配合外键约束完全可以避免ID匹配错误。注意填充顺序必须是先填充genres、movies两张主表,最后填充中间关联表。


步骤1:配置Seeder执行顺序

在database/seeders/DatabaseSeeder.php中按顺序注册Seeder,保证主表数据先于中间表生成:

public function run()
{
    $this->call([
        GenreSeeder::class,
        MovieSeeder::class,
        GenreMovieSeeder::class, // 中间表Seeder最后执行
    ]);
}

步骤2:编写主表Seeder

先写入两张主表的测试数据,示例如下:

GenreSeeder

// database/seeders/GenreSeeder.php
<?php

namespace Database\Seeders;

use App\Models\Genre;
use Illuminate\Database\Seeder;

class GenreSeeder extends Seeder
{
    public function run()
    {
        $genres = [
            ['name' => '动作'],
            ['name' => '喜剧'],
            ['name' => '科幻'],
            ['name' => '爱情'],
            ['name' => '恐怖'],
            ['name' => '犯罪'],
        ];
        foreach ($genres as $genre) {
            Genre::create($genre);
        }
    }
}

MovieSeeder

// database/seeders/MovieSeeder.php
<?php

namespace Database\Seeders;

use App\Models\Movie;
use Illuminate\Database\Seeder;

class MovieSeeder extends Seeder
{
    public function run()
    {
        $movies = [
            ['name' => '流浪地球2', 'status' => 1, 'image_path' => 'images/lldq2.jpg'],
            ['name' => '满江红', 'status' => 1, 'image_path' => 'images/mjh.jpg'],
            ['name' => '消失的她', 'status' => 1, 'image_path' => 'images/xsdt.jpg'],
            ['name' => '孤注一掷', 'status' => 1, 'image_path' => 'images/gzyz.jpg'],
        ];
        foreach ($movies as $movie) {
            Movie::create($movie);
        }
    }
}

步骤3:编写中间表Seeder

提供两种常用的填充逻辑,按需选择即可:

方案A:随机生成关联关系

适合测试场景,给每个分类随机绑定2-3部电影:

// database/seeders/GenreMovieSeeder.php
<?php

namespace Database\Seeders;

use App\Models\Genre;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;

class GenreMovieSeeder extends Seeder
{
    public function run()
    {
        // 清空中间表旧数据,避免唯一键冲突
        DB::table('genre_movie')->truncate();

        $allMovieIds = \App\Models\Movie::pluck('id');
        // 遍历所有分类,随机绑定电影
        Genre::all()->each(function ($genre) use ($allMovieIds) {
            $randomMovieIds = $allMovieIds->random(rand(2, 3))->toArray();
            // attach方法会自动写入当前分类ID和选中的电影ID到中间表
            $genre->movies()->attach($randomMovieIds);
        });
    }
}

方案B:固定绑定关联关系

适合需要精确控制电影和分类对应关系的场景,按名称匹配对应模型,不需要手动查ID:

public function run()
{
    DB::table('genre_movie')->truncate();

    // 自定义绑定规则:键为电影名,值为对应分类名数组
    $bindMap = [
        '流浪地球2' => ['动作', '科幻'],
        '满江红' => ['动作', '喜剧'],
        '消失的她' => ['爱情', '恐怖'],
        '孤注一掷' => ['动作', '犯罪'],
    ];

    foreach ($bindMap as $movieName => $genreNames) {
        $movie = \App\Models\Movie::where('name', $movieName)->first();
        if (!$movie) continue;
        $genreIds = Genre::whereIn('name', $genreNames)->pluck('id');
        // sync方法会自动同步关联,自动删除该电影旧的无效关联
        $movie->genres()->sync($genreIds);
    }
}

多对多关联操作方法说明:

  • attach($ids):追加传入ID对应的关联记录,不影响已有绑定关系
  • detach($ids):删除传入ID对应的关联记录
  • sync($ids):全量同步关联,仅保留传入ID对应的绑定关系,其余旧关联会自动清除

内容的提问来源于stack exchange,提问作者Illia

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 04:09:16