
在 Laravel 8 迁移中,不能在 Schema::create() 回调内创建模型实例并期望自动写入数据库;必须在表结构创建完成后,通过独立语句执行数据填充,且需确保模型支持批量赋值。
在 laravel 8 迁移中,不能在 `schema::create()` 回调内创建模型实例并期望自动写入数据库;必须在表结构创建完成后,通过独立语句执行数据填充,且需确保模型支持批量赋值。
在 Laravel 应用开发中,常需在数据库首次迁移时预置基础数据(如默认模板、角色、状态等)。但初学者容易误将模型创建逻辑嵌套在 Schema::create() 的闭包中——这仅会实例化 PHP 对象,不会触发数据库写入,因为 Schema::create() 仅负责定义表结构,不执行 Eloquent 操作。
✅ 正确做法:分离结构定义与数据填充
迁移文件应严格分为两个阶段:
- 建表(Schema::create)
- 插数据(表创建成功后,调用模型静态方法)
以下是推荐的完整迁移实现:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use App\Models\Template; // 确保导入正确的模型命名空间
return new class extends Migration
{
public function up(MigrationBuilder $migration): void
{
Schema::create('templates', function (Blueprint $table) {
$table->id();
$table->string('name')->unique();
$table->timestamps();
});
// ✅ 数据插入必须放在 Schema::create 之后
// 使用 Collection::times 链式创建 3 条记录
\Illuminate\Support\Collection::times(3, function ($i) {
Template::create([
'name' => 'Template ' . ($i + 1) // $i 从 1 开始计数更直观
]);
});
}
public function down(MigrationBuilder $migration): void
{
Schema::dropIfExists('templates');
}
};⚠️ 关键前提:模型必须配置可批量赋值
Template::create() 调用依赖 Laravel 的批量赋值保护机制。若未显式声明,Eloquent 会拒绝所有字段赋值,导致插入静默失败或抛出 MassAssignmentException。
请确认你的 Template 模型中已正确定义 $fillable 属性:
// app/Models/Template.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Template extends Model
{
protected $fillable = ['name']; // ✅ 允许 name 字段被批量赋值
}? 替代方案:若需更高控制力(如设置 created_at/updated_at 或验证),可使用 new Template([...])->save(),但 create() 更简洁、符合 Laravel 惯例。
? 补充说明与最佳实践
- 不要在 up() 中混用 DB::insert() 或原生 SQL 插入初始数据:虽可行,但丧失 Eloquent 的事件(如 creating/created)、类型转换、软删除兼容性等优势;
- 避免在迁移中执行耗时操作:如需插入数千条数据,请改用 Seeder(php artisan db:seed),迁移应聚焦于“结构+极少量核心种子”;
- 回滚安全:down() 方法中仅需删除表,无需手动删数据——因为 Schema::dropIfExists() 已涵盖;
- 环境隔离:此类初始化数据通常只应在本地/测试环境运行;生产环境建议通过部署脚本或独立 Seeder 控制。
掌握这一模式,你就能稳健地在每次 php artisan migrate 时自动构建带初始内容的数据库,为后续开发打下可靠基础。










