我有一个使用 DoctrineMigrations 包的 Symfony 项目,我有一个非常简单的问题:当我运行迁移时(例如,当我将更新推送到生产时),如何将数据插入数据库?
例如:我有一个 Entity,它是 add 类型。该实体是:
private $addType; // String
private $type1; // Boolean
private $type2; // Boolean
private $type3; // Boolean
我添加另一个字段 (
$type4
),并且我想向数据库添加一条新记录,其值如下:
$addType = 'Type number 4';
$type1 = false;
$type2 = false;
$type3 = false;
$type4 = true;
如何使用 DoctrineMigrations 来完成此操作?可以吗?
按照另一个答案中的建议使用实体管理器不是一个好主意,因为它会在以后带来麻烦。
在第一次迁移中,我创建了一个包含 users 的表,并通过
$em->persist($user);
填充了一些用户,一开始看起来不错。
但是一个月后,我在我的用户模型中添加了一个
phone
列。 Doctrine 在第一次迁移中使用此列生成 INSERT 语句,由于不存在列phone
,该语句失败。当然,在第一次迁移中它还不存在。所以最好使用纯 SQL INSERT。
我刚刚问了一个相关的相关问题。
可以使用迁移包将数据添加到数据库。如果您添加新属性并使用学说映射,那么
php app/console doctrine:migrations:diff
命令将生成一个新的迁移文件。您可以使用以下语法将插入语句放入此文件中:
$this->addSql('INSERT INTO your_table (name) VALUES ("foo")');
请确保将其放在自动生成的架构更改之后。如果您想将架构更改和数据更改分开,那么您可以使用
php app/console doctrine:migrations:generate
创建一个空的迁移文件来放入插入语句。
就像我在相关问题中所说,这是一种方法,但如果您想更改数据库中的此数据,则需要手动创建这些数据。
编辑:
由于这个答案似乎得到了一些观点,我认为值得添加的是,为了更清楚地将数据更改与模式更改分开,有一个可以重写的
postUp
方法,并且将在 up
方法之后调用。
确实如此,如果您知道如何格式化数组;
$this->connection->insert('user', ['id' => 1, 'gender' => 'Male']);
我已经“找到”了解决问题的正确方法(使用我的实体类在运行迁移后插入数据)。
这里是:https://stackoverflow.com/a/25960400
想法是将迁移声明为
ContainerAware
,然后从 postUp
函数中调用 DI 来获取 EntityManager
。这非常简单,您可以使用所有实体和存储库。
// ...
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class Version20130326212938 extends AbstractMigration implements ContainerAwareInterface
{
private $container;
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
public function up(Schema $schema)
{
// ... migration content
}
public function postUp(Schema $schema)
{
$em = $this->container->get('doctrine.orm.entity_manager');
// ... update the entities
}
}
当您创建新字段时,您需要输入此注释“
options={"default":1}
”,它应该可以工作。
/**
* @var boolean
* @ORM\Column(name="type4", type="boolean", options={"default":1})
*/
private $type4 = true;
我花了一些时间才弄清楚这一点:)
这对我来说是一个很好的解决方案。只需使用 bin/console make:migration ,生成迁移时只需编辑 if 并添加“DEFAULT TRUE”: $this->addSql('ALTER TABLE 事件 ADD active TINYINT(1) NOT NULL DEFAULT TRUE');
使用 Symfony 7 的简短摘要
<?php
// symfony 7
// php 8.2
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
use App\Entity\CustomEntity;
final class Version20230101000000 extends AbstractMigration
{
/** @var CustomEntity[] */
private static function getData(): array
{
return [
(new CustomEntity())->setProperty('value'),
(new CustomEntity())->setProperty('nextValue'),
];
}
public function up(Schema $schema): void
{
// table structure is create here
}
public function postUp(Schema $schema): void
{
foreach(self::getData() as $entity) {
$this->connection->insert(
table:'table_name',
data: ['property' => $entity->getProperty()]
);
}
}
public function down(Schema $schema):void
{
// no changes required
}
}
Fixtures 是为在开发环境中处理示例数据而构建的。因此,它们不是用来阻止数据进入高效数据库的选项。
对于小组默认条目,可以使用迁移文件。如果您需要防止大量数据,请考虑构建一个 TaskRunner 并分块工作。
在迁移中填写日期听起来不是一个好主意,这不是它的责任,symfony 有办法做到这一点。 https://symfony.com/doc/current/bundles/DoctrineFixturesBundle/index.html