我有以下迁移:
Schema::create('items', function(Blueprint $table) {
$table->uuid('id')->primary();
// more columns ...
});
现在,我们要添加一个额外的自动增量列:
Schema::table('items', function(Blueprint $table) {
$table->dropPrimary('id');
$table->rename('id', 'SystemId')->change();
$table->id();
});
问题:SQLite 不允许更改主键
解决方案:建议删除表并使用更改后的架构创建
当然,这在理论上是可行的,但将代码从第一次迁移复制到第二次迁移绝非干巴巴的事情。所以我的问题是:还有其他方法可以实现这一目标吗?
所以,我终于想出了一个足够通用、可重用的解决方案。如果能包含在 Laravel 中就好了,但打包的可能性更大。
use Doctrine\DBAL\Schema\Table;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
class ExtendedSQLiteAlterTableMigration extends Migration
{
public function extendedAlterTable(string $tableName, callable $callback)
{
/** @var \Doctrine\DBAL\Schema\AbstractSchemaManager */
$schemaManager = DB::connection()->getDoctrineSchemaManager();
/** @var \Doctrine\DBAL\Schema\Table */
$table = $this->getTempTable($schemaManager, $tableName);
call_user_func($callback, $table);
$tempName = $table->getName();
//$schemaManager->renameTable($tableName, $tempName);
$schemaManager->createTable($table);
$schemaManager->dropTable($tableName);
$schemaManager->renameTable($tempName, $tableName);
}
private function getTempTable($schemaManager, string $name)
{
$columns = $schemaManager->listTableColumns($name);
$foreignKeys = [];
//if ($this->_platform->supportsForeignKeyConstraints()) {
$foreignKeys = $schemaManager->listTableForeignKeys($name);
//}
$indexes = $schemaManager->listTableIndexes($name);
return new Table("temp_$name", $columns, $indexes, [], $foreignKeys);
}
}
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddAutoIncrementPrimaryKeyToTestTable extends ExtendedSQLiteAlterTableMigration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$this->extendedAlterTable('test', function(Table $table) {
$table->dropPrimaryKey();
$table->addColumn('id', 'bigint', [
'autoincrement' => true,
]);
$table->setPrimaryKey([ 'id' ]);
});
}
}
这遵循 SQLite 网站上的说明
创建 SQLite 表后,您无法对其进行任何重大修改。正如您所说,可接受的建议解决方案是创建一个具有正确要求的新表并将数据复制到其中,然后删除旧表。这是唯一的方法。
关于此的官方文档:http://sqlite.org/faq.html#q11