我有一个名为产品的映射实体,只有两列:id
和name
。
如果我手动添加另一列,即直接使用SQL语句stock_qty
,那么模式更新工具将会远程。
如何防止Doctrine删除未映射到我的实体的自定义列?
答案 0 :(得分:0)
您可以定义onSchemaColumnDefinition或onSchemaAlterTableRemoveColumn事件,并忽略这些列。
使用onSchemaColumnDefinition事件
在捆绑包中,创建例如。 src / AppBundle / EventListener / MyEventListener.php:
namespace AppBundle\EventListener;
use Doctrine\DBAL\Event\SchemaColumnDefinitionEventArgs;
use Doctrine\DBAL\Event\SchemaAlterTableRemoveColumnEventArgs;
class MyEventListener
{
public function onSchemaAlterTableRemoveColumn(SchemaAlterTableRemoveColumnEventArgs $args)
{
$tableColumn = $args->getColumn();
$table = $args->getTableDiff();
if($table->name == 'tableName' && $tableColumn->getName() == 'columnName') {
$args->preventDefault();
}
}
}
然后,在您的服务中注册事件监听器:
services:
AppBundle\EventListener\MyEventListener:
tags:
- { name: doctrine.event_listener, event: onSchemaAlterTableRemoveColumn }
类似,您可以这样做:
使用onSchemaAlterTableRemoveColumn事件
在捆绑包中,创建例如。 src / AppBundle / EventListener / MyEventListener.php:
namespace AppBundle\EventListener;
use Doctrine\DBAL\Event\SchemaColumnDefinitionEventArgs;
use Doctrine\DBAL\Event\SchemaAlterTableRemoveColumnEventArgs;
class MyEventListener
{
public function onSchemaColumnDefinition(SchemaColumnDefinitionEventArgs $args)
{
$tableColumn = $args->getTableColumn();
$table = $args->getTable();
if($table == 'tableName' && $tableColumn['Field'] == 'columnName') {
$args->preventDefault();
}
}
}
然后,在您的 services.yml 中注册事件监听器:
services:
AppBundle\EventListener\MyEventListener:
tags:
- { name: doctrine.event_listener, event: onSchemaColumnDefinition }
运行时:
php bin/console doctrine:schema:update --force
应忽略指定的列。 (在这种情况下,“ tableName”。“ columnName”将不会被删除)
参考文献:
答案 1 :(得分:0)
Jannes Botis的回答非常有帮助。我有一些额外的问题,即使该列被忽略,索引和外键也被删除。此外,向下迁移继续尝试重新添加相关列。
接下来是基于其他答案的扩展解决方案。
<?php
namespace App\Listener\Doctrine;
use Doctrine\DBAL\Event\SchemaAlterTableAddColumnEventArgs;
use Doctrine\DBAL\Event\SchemaAlterTableRemoveColumnEventArgs;
class DoctrineListener
{
protected $ignoreFields;
public function __construct($doctrineIgnoreFields)
{
$this->ignoreFields = $doctrineIgnoreFields;
}
public function onSchemaAlterTableAddColumn(SchemaAlterTableAddColumnEventArgs $args)
{
$tableDiff = $args->getTableDiff();
if (in_array($tableDiff->name, array_keys($this->ignoreFields))) {
$tableName = $tableDiff->name;
$tableColumn = $args->getColumn();
if (in_array($tableColumn->getName(), $this->ignoreFields[$tableName])) {
$columnName = $tableColumn->getName();
if ($tableColumn->getName() == $columnName) {
$tableDiff = $args->getTableDiff();
unset($tableDiff->addedColumns[$columnName]);
foreach ($args->getTableDiff()->addedIndexes as $index => $addedIndex) {
foreach ($addedIndex->getColumns() as $column) {
if ($column === $columnName) {
unset($tableDiff->addedIndexes[$index]);
$args->preventDefault();
}
}
}
foreach ($args->getTableDiff()->addedForeignKeys as $index => $foreignKey) {
foreach ($foreignKey->getColumns() as $column) {
if ($column === $columnName) {
unset($tableDiff->addedForeignKeys[$index]);
$args->preventDefault();
}
}
}
}
}
}
}
public function onSchemaAlterTableRemoveColumn(SchemaAlterTableRemoveColumnEventArgs $args)
{
$tableDiff = $args->getTableDiff();
if (in_array($tableDiff->name, array_keys($this->ignoreFields))) {
$tableName = $tableDiff->name;
$tableColumn = $args->getColumn();
if(in_array($tableColumn->getName(), $this->ignoreFields[$tableName])) {
$columnName = $tableColumn->getName();
$args->preventDefault();
unset($tableDiff->removedColumns[$columnName]);
foreach ($args->getTableDiff()->removedIndexes as $index => $removedIndex) {
foreach ($removedIndex->getColumns() as $column) {
if ($column === $columnName) {
unset($tableDiff->removedIndexes[$index]);
$args->preventDefault();
}
}
}
foreach ($args->getTableDiff()->removedForeignKeys as $index => $removedForeignKey) {
foreach ($removedForeignKey->getColumns() as $column) {
if ($column === $columnName) {
unset($tableDiff->removedForeignKeys[$index]);
$args->preventDefault();
}
}
}
}
}
}
}
配置:
services:
# default configuration for services in *this* file
_defaults:
...
bind:
$doctrineIgnoreFields:
'table_a':
- 'column_a'
- 'column_b'
'table_b':
- 'column_c'
- 'column_d'
App\Listener\Doctrine\DoctrineListener:
tags:
- { name: doctrine.event_listener, event: onSchemaAlterTableAddColumn }
- { name: doctrine.event_listener, event: onSchemaAlterTableRemoveColumn }
此解决方案已在symfony 4.4上进行了测试