【问题标题】:Laravel 5 migration: error while renaming columnsLaravel 5 迁移:重命名列时出错
【发布时间】:2015-07-28 00:44:14
【问题描述】:

我是 Laravel 的新手,并且有这样的迁移:

public function up()
{
    Schema::table('mytable', function(Blueprint $table)
    {
        $table->renameColumn('mycol', 'old_mycol');
        $table->string('mycol', 100);
    });
}

当我运行它时,我得到了错误:

[PDO异常]
SQLSTATE [42S21]:列已存在:1060 列名重复 'mycol'

我最终将其拆分为 2 个单独的迁移并且效果很好,但我不明白为什么一次性完成它是一个问题。

【问题讨论】:

    标签: php mysql laravel-5


    【解决方案1】:

    这是因为 Laravel 会在执行迁移时隐式地将任何添加新列或修改现有列的命令放在 commands 数组的最开头。以下代码直接取自Illuminate\Database\Schema\Blueprint 类。

    /**
     * Get the raw SQL statements for the blueprint.
     *
     * @param  \Illuminate\Database\Connection  $connection
     * @param  \Illuminate\Database\Schema\Grammars\Grammar  $grammar
     * @return array
     */
    public function toSql(Connection $connection, Grammar $grammar)
    {
        $this->addImpliedCommands();
    
        $statements = array();
    
        // Each type of command has a corresponding compiler function on the schema
        // grammar which is used to build the necessary SQL statements to build
        // the blueprint element, so we'll just call that compilers function.
        foreach ($this->commands as $command)
        {
            $method = 'compile'.ucfirst($command->name);
    
            if (method_exists($grammar, $method))
            {
                if ( ! is_null($sql = $grammar->$method($this, $command, $connection)))
                {
                    $statements = array_merge($statements, (array) $sql);
                }
            }
        }
    
        return $statements;
    }
    
    /**
     * Add the commands that are implied by the blueprint.
     *
     * @return void
     */
    protected function addImpliedCommands()
    {
        if (count($this->getAddedColumns()) > 0 && ! $this->creating())
        {
            array_unshift($this->commands, $this->createCommand('add'));
        }
    
        if (count($this->getChangedColumns()) > 0 && ! $this->creating())
        {
            array_unshift($this->commands, $this->createCommand('change'));
        }
    
        $this->addFluentIndexes();
    }
    

    从上面的代码可以看出,在toSql 方法中,有一个对addImpliedCommands 的调用,其中可能会将多个命令添加到对象的命令数组的开头。这会导致在重命名命令之前首先执行新的mycol 列的命令。

    要解决这个问题,您并不真的需要创建两个迁移。在同一个迁移中,您可以像这样简单地调用Schema::table() 两次:

    Schema::table('mytable', function(Blueprint $table)
    {
        $table->renameColumn('mycol', 'old_mycol');
    });
    
    Schema::table('mytable', function(Blueprint $table)
    {
        $table->string('mycol', 100);
    });
    

    【讨论】:

    • 哇,非常感谢。我在这里的第一个问题,回答得如此明确。我喜欢它!谢谢!
    猜你喜欢
    • 2020-06-22
    • 2016-03-14
    • 2018-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-06
    • 2018-12-10
    • 2015-10-18
    相关资源
    最近更新 更多