什么是 Seeding
Seeding(填充)是向数据库写入示例数据或初始数据的机制。
在搭建开发环境或运行自动化测试时,通常需要预先有一定的数据。由于每次手动输入数据非常繁琐,可以将其整理为可重复执行的 Seeder。
Seeder 类存放在 database/seeders 目录下。默认会提供一个 DatabaseSeeder 类。
创建 Seeder
使用 make:seeder Artisan 命令生成一个新的 Seeder 类。
php artisan make:seeder UserSeeder
生成的文件会放在 database/seeders/UserSeeder.php。
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class UserSeeder extends Seeder
{
/**
* 执行 Seeder
*/
public function run(): void
{
// 在这里编写数据写入逻辑
}
}
编写 Seeder
在 run() 方法中编写数据写入逻辑。你可以使用 DB 门面或 Eloquent 模型来插入数据。
使用 DB 门面
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
class UserSeeder extends Seeder
{
public function run(): void
{
DB::table('users')->insert([
[
'name' => '山田太郎',
'email' => '[email protected]',
'password' => Hash::make('password'),
'created_at' => now(),
'updated_at' => now(),
],
[
'name' => '铃木花子',
'email' => '[email protected]',
'password' => Hash::make('password'),
'created_at' => now(),
'updated_at' => now(),
],
]);
}
}
使用 Eloquent 模型
use App\Models\User;
use Illuminate\Support\Facades\Hash;
public function run(): void
{
User::create([
'name' => '管理员',
'email' => '[email protected]',
'password' => Hash::make('password'),
]);
}
Seeding 执行期间,批量赋值保护会自动被禁用。你无需关心 $fillable 或 $guarded 的配置就可以插入数据。
与模型工厂结合使用
如果需要大量测试数据,与模型工厂结合使用会非常方便。工厂能够批量生成带有随机字段的假数据。
use App\Models\User;
use App\Models\Post;
public function run(): void
{
// 创建 10 位用户
User::factory(10)->create();
// 为每位用户创建 3 条帖子
User::factory(5)
->hasPosts(3)
->create();
}
关于工厂的详细用法请参阅 Eloquent 工厂文档。
DatabaseSeeder 的用法
DatabaseSeeder 是统一管理多个 Seeder 的入口。使用 call() 方法指定要执行的 Seeder。
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
public function run(): void
{
$this->call([
UserSeeder::class,
PostSeeder::class,
CommentSeeder::class,
]);
}
}
Seeder 会按照传给 call() 的顺序执行。如果存在外键约束,请让被引用的表先填充(如:users → posts)。
运行 Seeder
运行所有 Seeder
将会调用 DatabaseSeeder,然后按顺序执行通过 call() 指定的 Seeder。
只执行特定 Seeder
使用 --class 选项可以指定要执行的 Seeder 类。
php artisan db:seed --class=UserSeeder
与迁移一起执行
在 migrate:fresh 命令上添加 --seed 选项,可以先重建所有数据表,然后统一执行 Seeder。
php artisan migrate:fresh --seed
如果只需执行特定 Seeder,可以使用 --seeder 选项。
php artisan migrate:fresh --seed --seeder=UserSeeder
migrate:fresh 会删除并重建所有表,现有数据都会丢失,因此不要在生产环境中使用。
在生产环境中执行
在生产环境执行 Seeding 时会出现确认提示。如果不需要确认,可以使用 --force 标记。
php artisan db:seed --force
在生产环境执行 Seeding 可能造成数据被覆盖或丢失。执行前请务必做好备份。
抑制模型事件
如果希望在 Seeding 期间阻止 creating、created 等模型事件被触发,可以使用 WithoutModelEvents trait。
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
class DatabaseSeeder extends Seeder
{
use WithoutModelEvents;
public function run(): void
{
$this->call([
UserSeeder::class,
]);
}
}
该 trait 也会作用于通过 call() 调用的子 Seeder。
实战示例:博客应用的 Seeder
以一个包含用户与帖子的博客应用为例,来搭建初始数据。
// database/seeders/UserSeeder.php
class UserSeeder extends Seeder
{
public function run(): void
{
User::factory(10)->create();
}
}
// database/seeders/PostSeeder.php
class PostSeeder extends Seeder
{
public function run(): void
{
// 为每位用户创建 2 到 5 条帖子
User::all()->each(function ($user) {
Post::factory(rand(2, 5))->create([
'user_id' => $user->id,
]);
});
}
}
// database/seeders/DatabaseSeeder.php
class DatabaseSeeder extends Seeder
{
public function run(): void
{
$this->call([
UserSeeder::class,
PostSeeder::class, // 在 users 之后执行
]);
}
}
执行步骤:
php artisan migrate:fresh --seed
下一步
Eloquent 入门
学习如何通过 Eloquent ORM 获取和操作已通过 Seeder 写入的数据。