В ситуациях, когда необходимо совершать действия над таблицей, которая уже содержит в себе какие-либо данные, может возникнуть неприятная ошибка: "Mysql error 1452 - Cannot add or update a child row: a foreign key constraint fails".
Возникает она вследствие того, что мы пытаемся изменить существующую запись таким образом, что нарушается целостность.
Например, присвоение полю ключа, который не существует в родительской таблице. Или создание нового внешнего ключа для поля, которое не должно быть NULL, в таблице, которая уже содержит некоторое количество записей. Последняя проблема у меня и возникла. Необходимо было решение, и оно было найдено.
Решение простое как пять копеек. Нам необходимо избавиться от NULL-значений в поле, на которое навешивается внешний ключ.
Предположим, что вы уже отредактировали схему соответствующим образом и она имеет примерно следующее содержание:
Human:
columns:
name: { type: string(255), notnull: true }
human_status_id: { type: integer, notnull: true }
relations:
HumanStatus:
local: human_status_id
foreign: id
onDelete: CASCADE
HumanStatus:
columns:
name: { type: string, notnull: true }
После успешной генерации миграций должны появиться два файла миграций: один будет содержать создание таблиц, а вторая создание связей между ними. Именно второй файл мы и будем редактировать. Нам это никто не запрещает.
Итак, как я уже сказал, нам необходимо избавиться от NULL-значений. Для этого мы поправим вторую миграцию примерно таким образом:
public function up()
{
$conn = Doctrine_Manager::getInstance()->getCurrentConnection();
$oHumanStatus = new HumanStatus();
$oHumanStatus->setName('Temp');
$oHumanStatus->save();
Doctrine_Query::create()
->update()
->from('Human')
->set('human_status_id', $oHumanStatus->getId())
->execute();
$this->createForeignKey('human', 'human_human_status_id_human_status_id', array(
'name' => 'human_human_status_id_human_status_id',
'local' => 'human_status_id',
'foreign' => 'id',
'foreignTable' => 'human_status',
'onUpdate' => '',
'onDelete' => 'CASCADE',
));
$this->addIndex('human', 'human_human_status_id', array(
'fields' =>
array(
0 => 'human_status_id',
),
));
}
Думаю, основная идея понятна. Если нет нужды в создании новой записи в таблице HumanStatus, можно поискать уже существующие. Все зависит от вашей ситуации.
Далее накатываем обе миграции. Все должно пройти успешно. Если нет — читайте мануалы дальше. Возможно, это не ваш случай.
P.S. Не оставляйте die() в up() или down() методах миграции. Иначе она не накатится.