经过几次过度设计和过于聪明的解决方案尝试后,我认为以下是该问题的可行解决方案。
tl;博士:
- 从无到有构建架构的迁移两侧的书挡迁移。
- 更新项目。
- 迁移。
- 删除书挡和所有以前的迁移。
migrations
从表中删除记录。
第一个书挡重命名受影响的表。第二个书挡将数据从重命名的表复制到新表,然后删除重命名的表。
注意:您可以在书挡内做任何您喜欢的事情,这只是最低要求。
因此,假设您对迁移进行以下操作:
- 2017_09_05_000000_create_some_table.php
- 2017_09_05_000001_add_field_x_to_some_table.php
- 2017_09_05_000002_add_field_y_to_some_table.php
- 2017_09_05_000003_add_field_z_to_some_table.php
我们将创建另一个迁移:
- 2017_09_05_000004_pre_refresh.php
我们将根据我们现在拥有的知识创建另一个迁移:
- 2017_09_05_000005_create_some_table.php
我们将创建最后一个书挡,其中将发生数据迁移:
- 2017_09_05_000006_post_refresh.php
前四个迁移将不会运行,因为它们已经运行过。
/** 2017_09_05_000004_pre_refresh.php */
class PreRefresh extends Migration
{
public function up()
{
$prefix = 'zz_';
$tablesToRename = [
'foos',
'bars'
];
foreach($tablesToRename as $table) {
Schema::rename($table, $prefix . $table);
}
}
}
无需降价,因为这是一次性交易。这将首先运行,这将导致数组中列出的所有表都被重命名。然后将运行合并的(优化的)迁移。
/** 2017_09_05_000006_post_refresh.php */
class PostRefresh extends Migration
{
public function up()
{
// Do what you need to do.
// If you cannot use your models, just use DB::table() commands.
$foos = DB::table('zz_foos')->get();
foreach ($foos as $foo) {
DB::table('foo')->insert([
'id' => $foo->id,
'created_at' => $foo->created_at,
'updated_at' => $foo->updated_at
]);
}
$bars = DB::table('zz_bars')->get();
foreach ($bars as $bar) {
DB::table('bar')->insert([
'id' => $bar->id,
'created_at' => $bar->created_at,
'updated_at' => $bar->updated_at,
'foo_id' => $bar->foo_id
]);
}
// Tear down.
$prefix = 'zz_';
$tablesToRename = [
'foo',
'bar'
];
foreach ($tablesToRename as $table) {
DB::statement('SET FOREIGN_KEY_CHECKS=0');
Schema::dropIfExists($prefix . $table);
DB::statement('SET FOREIGN_KEY_CHECKS=1');
}
}
}
运行此命令后,您可以删除pre_refresh
之前和之前的所有迁移。以及post_refresh
. 然后您可以进入migrations
表格并删除这些迁移的条目。
删除条目并非完全必要,但如果您migrate:rollback
会收到错误消息,指出无法找到迁移。
注意事项
- 如果架构在设计上不是模块化的,那么它可能会非常麻烦。但是,如果您已将代码分成服务,它似乎会更容易一些。
- 迁移期间的 Laravel 错误处理和消息非常有限;因此,调试可能很困难。
- 强烈建议从您的应用程序/服务中最稳定的表开始。此外,从您的应用程序的基础开始,也可能证明是有益的。
注意:当我在生产中实际这样做时,而不仅仅是我的本地(一遍又一遍),如果没有更好的答案,那么我会接受这个。
注意事项
/config/app
如果您通过谨慎的迁移将应用程序分解为服务提供者,那么您可以在运行迁移时注释掉服务提供者。这样,您就可以为现在的基线服务创建一个批处理。因此,假设您有以下迁移,其中每个字母代表一个迁移,每个重复的字母代表相同的服务:
合并服务 A 后:
合并 B 后:
合并 C 后:
更新
到目前为止,从 54 次迁移到 27 次。我什至从大型up()
和down()
方法中提取了一些 Schema 更改,并将它们分开迁移。这里很好的副作用是批次。我从支持其他所有内容的基表开始迁移;因此,回滚更多的是服务。