2015-05-16 3 views
1

Я новичок в Laravel и имеют миграции, как это:Laravel 5 миграции: ошибка при переименовании столбцов

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

Когда я бегу, я получаю ошибку:

[PDOException]
SQLSTATE[42S21]: Column already exists: 1060 Duplicate column name 'mycol'

Я закончил разбив его на две отдельные миграции, и это сработало нормально, но я не понимаю, почему это происходит за один проход.

ответ

2

Это связано с тем, что Laravel неявно помещает любые команды, которые добавляют новые или изменяют существующие столбцы в самом начале массива команд при выполнении миграции. Следующий код берется непосредственно из класса 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 будет выполнена перед командой rename.

Чтобы обойти это, вам не нужно действительно нужно создать две миграции. В той же миграции вы можете просто позвонить Schema::table() дважды так:

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

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

Ничего себе, спасибо огромное. Мой первый вопрос здесь ответил так явно. Я люблю это! Спасибо! – dorian108

Смежные вопросы