在部署使用 Doctrine ORM 的 Symfony2 应用程序时,您如何处理迁移?
我一直在使用 DoctrineMigrationsBundle。如果您避免在迁移的 postUp() 部分尝试使用实体,它会很好地工作。但是,如果这样做,就会遇到麻烦。
下面是一些伪代码来解释这个问题:
/* Migration1.php */
class Migration1 extends... implements ContainerAwareInterface {
public function up(...) {
query("CREATE TABLE entities WITH COLUMNS col1, col2;");
}
public function postUp(...) {
$e = new Entity();
$e->setCol1("value1");
$e->setCol2("value2");
$entityManager->persist($e);
}
}
/* Migration2.php */
class Migration2 extends... implements ContainerAwareInterface {
public function up(...) {
query("ALTER TABLE entities ADD col3");
}
}
实际案例一:
- 开发人员更改应用程序代码并准备 Migration1
- 代码部署在服务器上,包括运行迁移
- 开发人员更改应用程序代码并准备 Migration2
- 代码部署在服务器上,包括运行迁移
一切正常。
实际案例2:
- 开发人员更改应用程序代码并准备 Migration1
- 开发人员更改应用程序代码并准备 Migration2
- 代码部署在服务器上,包括运行迁移
这是行不通的。为什么?
Migration1 的 postUp() 部分中的代码将使用最新的应用程序代码运行。这意味着 Doctrine ORM 将期望 col3 已经存在于实体表中。但是,由于此时 Migration2 尚未运行,因此不存在字段 col3。尝试在 Migration1 中保留新实体会导致 SQL 错误。
我想出了两个解决这个问题的想法:
- 部署新代码时,使用版本控制系统。分别检查每个提交,在每个提交中运行迁移,直到你到达最新的提交或者
- 不要使用 postUp() 来更改实体。在完成对数据库的所有结构更改后,在单独的脚本中处理实体。
请评论您在此问题上的经历并说明您是如何处理的。我相信你们中的一些人在实践中遇到过这种情况。
最佳答案
您描述的场景完美地表明(通常)不可能在 Doctrine Migrations 中使用实体。
因此,恐怕使这项工作以稳健的方式进行的唯一方法是降到 DBAL 级别:
public function postUp(...) {
$this->connection->insert('entities', [
'col1' => 'value1',
'col2' => 'value2'
]);
}
通过使用 DBAL 查询,将直接提供要使用的列,而不是通过应用程序代码定义的实体间接提供,不需要与当前表结构同步。
另见 "How to work with Doctrine migrations in Symfony" post 的第 4.2 节,它也描述了在 Doctrine Migrations 中使用实体的这个问题,尤其是下面的引用:
don't use entities within migrations, you must not rely on the entity (PHP) code, but on the database only!
关于php - 学说迁移 : How to avoid SQL errors in the postUp step?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35529309/