5.1 迁移与填充:打地基与备料


5.1 迁移与填充:打地基与备料

本节摘要:迁移把表结构变更写成带版本号的代码:每张表、每个字段的来龙去脉都有据可查、可回滚、可在任何一台机器上重放。本节讲迁移的生命周期、常用列类型与索引、改表的安全姿势,以及填充器与工厂怎么把空库变成有真实感数据的施工备料场。读完你能让全队在任何环境一键复原同一套数据库。

没有"地哪来的"这个困惑了

新手接项目常遇到这种对话:为什么我库里没有 orders 表?——群里发你一句"你手动跑一下那个 SQL"。表结构靠口头和散装 SQL 同步,是协作项目里最贵的坏习惯:环境不一致、字段没人说得清哪来的、改错了没法退。迁移(Migration)把地基施工变成代码:按时间排序的图纸,框架按序执行,migrations 表记录施工进度,支持整体回滚。

第一套迁移:给工单系统打地基

php artisan make:migration create_work_orders_table php artisan make:migration create_workers_table php artisan make:migration create_work_order_worker_table
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { public function up(): void { Schema::create('work_orders', function (Blueprint $table) { $table->id(); // 大整数自增主键 $table->foreignId('team_id')->constrained() // 外键:队组 ->cascadeOnDelete(); $table->string('title', 100); // 标题 $table->string('sn', 32)->unique(); // 工单号 唯一索引 $table->unsignedInteger('budget')->default(0); // 预算 存分 $table->enum('status', ['draft', 'open', 'building', 'done']) ->default('draft'); $table->timestamp('due_at')->nullable(); $table->timestamps(); // created_at 与 updated_at }); } public function down(): void { Schema::dropIfExists('work_orders'); // 回滚就拆表 } };

写迁移有三条纪律。up 与 down 必须严格互逆,回滚是迁移的价值所在;改历史迁移文件是大忌——已经提交的图纸只能新增一份"变更迁移"去改,就像施工中的地基不能推翻重画;外键约束配 cascadeOnDelete 前先想清楚级联范围,删队组连带删光工单是否符合业务。

多对多中间表(工单与施工人员的关联)是第三个迁移:

<?php Schema::create('work_order_worker', function (Blueprint $table) { $table->id(); $table->foreignId('work_order_id')->constrained()->cascadeOnDelete(); $table->foreignId('worker_id')->constrained()->cascadeOnDelete(); $table->string('role', 30)->default('worker'); // 在这个单子上的工种 $table->timestamps(); $table->unique(['work_order_id', 'worker_id']); // 防重复派工 });

常用执行命令一把过:

php artisan migrate # 执行所有待跑迁移 php artisan migrate:rollback # 回滚最后一批 php artisan migrate:fresh # 全部拆掉重来(会清数据,慎用) php artisan migrate:status # 看施工进度

图 5-1:迁移图纸的施工与回滚剖面

图 5-1:迁移图纸的施工与回滚剖面

填充与工厂:把空库变成备料场

表建好了是空的,开发与测试都需要"看起来真实"的数据。工厂(Factory)定义每条记录怎么造,填充器(Seeder)决定造多少、怎么组合:

<?php // database/factories/WorkOrderFactory.php namespace Database\Factories; use Illuminate\Database\Eloquent\Factories\Factory; class WorkOrderFactory extends Factory { public function definition(): array { return [ 'team_id' => \App\Models\Team::factory(), 'title' => $this->faker->randomElement([ '外墙翻新', '电路改造', '防水补漏', '门窗更换', ]) . '工单', 'sn' => 'WO' . $this->faker->unique()->numerify('########'), 'budget' => $this->faker->numberBetween(10000, 500000), 'status' => $this->faker->randomElement(['draft', 'open', 'building', 'done']), 'due_at' => $this->faker->dateTimeBetween('now', '+3 months'), ]; } }
<?php // database/seeders/DatabaseSeeder.php public function run(): void { \App\Models\Team::factory()->count(3)->create(); \App\Models\WorkOrder::factory()->count(50)->create(); } // 命令行:php artisan db:seed

工厂造出来的数据在第九章测试里是主角:每条测试用例造自己的数据、跑完回滚,互不污染。本节先把工厂建好,到验收时直接取用。

💡 关键直觉:迁移加工厂,等于数据库结构与其中的样例数据都进了版本管理。新人入职跑两条命令(migrate 加 db:seed)就能得到一份和生产结构一致、带真实感数据的库——这比任何入职文档都管用。

改表的安全姿势与常见坑

  • 加列给大表:新列给默认值或允许 null;变更请求分两步走(先加列、代码上线后再回填历史数据),别让一条迁移锁表十分钟。
  • 改列类型:需要 doctrine/dbal 支持或直接建新列迁移数据;改前在测试库演练一遍 down。
  • enum 改值:部分数据库对 enum 变更支持有限,业务上频繁扩状态的项目改用 string 加代码层枚举更稳。
  • 外键顺序:被引用的表必须先建,迁移文件按时间戳排序天然保证这一点,但回滚顺序恰好相反——down 里拆表要拆引用方再拆被引用方。

本节要点回顾

  • 迁移三纪律:up 与 down 互逆、历史图纸不回改、级联删除想清楚再写。
  • 地基图纸:列类型、唯一约束、外键、复合唯一索引,都在 up 里一次声明到位。
  • 备料两件套:工厂定义单条怎么造,填充器决定造多少,测试数据从此进了版本管理。
  • 改表安全:大表加列带默认值,变更分步上线,动结构前先在测试库跑 down。

地基打好了,接下来把施工队编制起来:下一节定义 Eloquent 模型,并用查询构造器写出复杂取数。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U