如何在Symfony 2中为数据库视图设置实体(学说)


How to set up entity (doctrine) for database view in Symfony 2

假设我有一个视图表。我想从它得到数据到一个实体。我可以(以及如何)创建实体类来做到这一点(不需要保存操作)?我只是想显示它们

公认的答案是正确的,但我想提供一些您可能需要考虑的额外建议:

将实体标记为只读。

将构造函数设为私有,这样只有Doctrine可以创建实例。

/**
 * @ORM'Entity(readOnly=true)
 * @ORM'Table(name="your_view_table")
 */
class YourEntity {
    private function __construct() {}
}

查询视图没有什么特别的——它只是一个虚表。这样布置你的实体的桌子,享受吧:

/**
 * @ORM'Entity
 * @ORM'Table(name="your_view_table")
 */
class YourEntity {
    // ...
}

前面的两个答案都是正确的,但是如果您使用学说迁移工具并执行schema:update,它将失败…

因此,除了将实体标记为只读并将构造函数设置为私有(在Ian Phillips的回答中解释):

/**
 * @ORM'Entity(readOnly=true)
 * @ORM'Table(name="your_view_table")
 */
class YourEntity {
    private function __construct() {}
}

你需要设置模式工具在执行schema:update…时忽略实体。

为了做到这一点,你只需要在你的bundle中创建这个命令,并在ignoredEntity列表中设置你的实体:

src/Acme/CoreBundle/命令/DoctrineUpdateCommand.php:

<?php
namespace Acme'CoreBundle'Command;
use Symfony'Component'Console'Input'InputOption;
use Symfony'Component'Console'Input'InputArgument;
use Symfony'Component'Console'Input'InputInterface;
use Symfony'Component'Console'Output'OutputInterface;
use Doctrine'ORM'Tools'SchemaTool;
class DoctrineUpdateCommand extends 'Doctrine'Bundle'DoctrineBundle'Command'Proxy'UpdateSchemaDoctrineCommand {
  protected $ignoredEntities = array(
      'Acme'CoreBundle'Entity'EntityToIgnore'
  );
  protected function executeSchemaCommand(InputInterface $input, OutputInterface $output, SchemaTool $schemaTool, array $metadatas) {
    /** @var $metadata 'Doctrine'ORM'Mapping'ClassMetadata */
    $newMetadatas = array();
    foreach ($metadatas as $metadata) {
      if (!in_array($metadata->getName(), $this->ignoredEntities)) {
        array_push($newMetadatas, $metadata);
      }
    }
    parent::executeSchemaCommand($input, $output, $schemaTool, $newMetadatas);
  }
}

(来源:Alexandru Trandafir Catalin:从这里获得:https://stackoverflow.com/a/25948910/1442457)

顺便说一句,这是我发现的唯一一种处理教条观点的方法…我知道这是个变通办法……如果有更好的方式我是开放或建议)

如果您正在使用原则迁移进行模式更新,那么除了上面的答案之外,下面的配置可以完美地工作。

/**
 * @ORM'Entity(readOnly=true)
 * @ORM'Table(name="view_table_name")
 */
class YourEntity {
    private function __construct() {}
}

直到这里与以上答案相同。在这里,你需要配置原则不绑定模式;

doctrine:
    dbal:
        schema_filter: ~^(?!view_)~

上面的过滤器定义过滤所有'view_'前缀的表以及视图,并且可以使用正则表达式扩展。只要确保你用'view_'前缀命名你的视图。

但是doctrine:schema:update——dump-sql仍然显示视图,我希望他们也能在schema更新中集成相同的过滤器。

我希望这个解决方案能帮助到其他人。

来源:http://symfony.com/doc/current/bundles/DoctrineMigrationsBundle/index.html manual-tables

除了上面的答案,你必须有一个视图实体和虚拟表的命名策略,例如:view_your_table,然后你必须添加下面的代码到原则中。禁用向视图创建新的迁移文件:schema_filter: ~^(?!view_)~

除了上面的答案,我还混合了一些示例代码来扩展DoctrineUpdateCommand

这是我的DoctrineUpdateCommand:

class DoctrineUpdateCommand extends UpdateSchemaDoctrineCommand{
   protected function executeSchemaCommand(InputInterface $input, OutputInterface $output, SchemaTool $schemaTool, array $metadatas) {
      $container = $this->getApplication()->getKernel()->getContainer();  
     $filterExpr = $container->get('doctrine')->getEntityManager()->getConnection()->getConfiguration()->getFilterSchemaAssetsExpression();
     $emptyFilterExpression = empty($filterExpr);
     /** @var $newMetadatas 'Doctrine'ORM'Mapping'ClassMetadata */
     $newMetadatas = array();
     foreach ($metadatas as $metadata) {
        if(($emptyFilterExpression||preg_match($filterExpr, $metadata->getTableName()))){
            array_push($newMetadatas, $metadata);
        }        
     }
     parent::executeSchemaCommand($input, $output, $schemaTool, $newMetadatas);
 }
}

Thanks for the right way

由于需要在Zend实现的数据库中引入一个视图,我花了一天的时间来研究这个问题。

如前所述,您应该创建一个实体,并且该实体必须具有Id()注释:

/**
 * @Doctrine'ORM'Mapping'Table(name="your_view")
 * @Doctrine'ORM'Mapping'Entity(readOnly=true)
 */
class YourViewEntity
{
    /**
     * @var SomeEntityInterface
     * @Doctrine'ORM'Mapping'Id()
     * @Doctrine'ORM'Mapping'OneToOne(targetEntity="SomeMainEntity", fetch="LAZY")
     * @Doctrine'ORM'Mapping'JoinColumn(nullable=false, referencedColumnName="id")
     */
    protected $some;
    /**
     * @var AnotherEntityInterface
     * @Doctrine'ORM'Mapping'ManyToOne(targetEntity="AnotherEntity", fetch="LAZY")
     * @Doctrine'ORM'Mapping'JoinColumn(nullable=false, referencedColumnName="id")
     */
    protected $another;
    // Make the constructor private so that only Doctrine can create instances.
    private function __construct() {}
}

也有私有构造函数,如Ian Phillips回答中所述。然而,这并不妨碍orm:schema-tool:update基于新实体创建一个表,试图覆盖我们的视图…尽管在生产环境中应该避免使用orm:schema-tool:update来支持迁移脚本,但对于开发目的来说,这是非常有用的。

由于schema_filter: ~^(?!view_)~似乎都不起作用,也被弃用了,我设法在Kamil Adryjanek页面上找到了一个技巧,该页面提供了将EventListenerSubscriber添加到实体管理器的选项,这将防止为我们创建表。我的实现如下:

class SkipAutogenerateTableSubscriber implements EventSubscriber
{
    public const CONFIG_KEY = "skip_autogenerate_entities";
    private $ignoredEntities = [];
    public function __construct($config)
    {
        if (array_key_exists(self::CONFIG_KEY, $config)) {
            $this->ignoredEntities = (array) $config[self::CONFIG_KEY];
        }
    }
    public function getSubscribedEvents()
    {
        return [
            ToolEvents::postGenerateSchema
        ];
    }
    public function postGenerateSchema(GenerateSchemaEventArgs $args)
    {
        $schema = $args->getSchema();
        $em = $args->getEntityManager();
        $ignoredTables = [];
        foreach ($this->ignoredEntities as $entityName) {
            $ignoredTables[] = $em->getClassMetadata($entityName)->getTableName();
        }
        foreach ($schema->getTables() as $table) {
            if (in_array($table->getName(), $ignoredTables)) {
                $schema->dropTable($table->getName());
            }
        }
    }
}

这不仅解决了orm:schema-tool的问题,而且还解决了doctrine/migrations模块的migrations:diff的问题。